problems with template metaprogramming

Started by
13 comments, last by EkEk 17 years, 8 months ago
Hello, I am having some problems with template metaprogramming in vc++. I am trying to get the following to compile:

#include <iostream>
#include <tchar.h>

#pragma inline_depth(255)
#pragma inline_recursion(on)

using namespace std;

template<double R> struct Sine
{
	enum { MaxTerms = 10 };
	static inline double sin()
	{
		return R * Series<R, 0, MaxTerms>::val();
	}
};

template <double R, int I, int MaxTerms> struct Series
{
	enum
	{
		Continue = I + 1 != MaxTerms,
		NxtI = ( I + 1 ) * Continue,
		NxtMaxTerms = MaxTerms * Continue
	};

	static inline double val()
	{
		return 1 - R*R/(2.0 * I + 2.0)/(2.0 * I + 3.0)*Series<R*Continue, NxtI, NxtMaxTerms>::val();
	};
};

template <> struct Series<0.0, 0, 0>
{
	static inline double val() { return 1.0; };
};

#define SineVal( r ) Sine<r>::sin()


int _tmain(int argc, _TCHAR* argv[])
{
	char ch;
	double val = 5.0;
	cout << SineVal(val) << endl;
	cin >> ch;
	return 0;
}

But i'm getting the following errors:


error C2993: 'double' : illegal type for non-type template parameter 'R'
error C2993: 'double' : illegal type for non-type template parameter 'R'


PS This came straight from Game Programming Gems, and was compiled using visual c++ 2005 express edition. Thanks for any assistance, exorcist_bob
Advertisement
1. template<double R> struct Sine { ... };
I don't believe any current compiler is supporting non-integral values as template parameters. That is: int, char, bool - yes, but float, double - nope.
EDIT: See Section 14.1 4 of The standard.
EDIT2: Section 14.1 7 of The standard explicitly disallows floating point values as template parameters.

2. #define SineVal( r ) Sine<r>::sin()
In expression: SineVal(val), val has to be a compile-time expression. Like: enum { val=5 }, or #define val 5. If 1. wasn't in the way, you could get away with SineVal(5.0).
MSVC 6 will allow for double and float non-type template arguments. For standard C++, you can use references to const double as non-type template arguments. It gets pretty ugly in instantiation for it to work, but compilers will generally expand the expressions out at compile time.
I dont really get what you are doing here,

Template parameters are not allowed to have a type (except class) is my understanding. This doesn't look like good C++ programming to me. Anyone?

Greetings.
I can't make those const, since I'm returning values. But if I make them references, I get these errors:

1>codetester.cpp(34) : error C2440: 'specialization' : cannot convert from 'double' to 'double &'
1>codetester.cpp(45) : error C2440: 'specialization' : cannot convert from 'double' to 'double &'
1>codetester.cpp(45) : error C2440: 'specialization' : cannot convert from 'int' to 'double &'
1>codetester.cpp(45) : see reference to class template instantiation 'Sine<R>' being compiled
1> with
1> [
1> R=0
1> ]
1>codetester.cpp(45) : error C2973: 'Sine' : invalid template argument 'int'
1>(16) : see declaration of 'Sine'

Thanks for the help!
exorcist_bob
Quote:Original post by Limitz
Template parameters are not allowed to have a type (except class) is my understanding. This doesn't look like good C++ programming to me. Anyone?


No, C++ allows several types of non-type template arguments including, roughly in order of most frequently encountered to least frequently encountered: constant integral expressions, enumerations, objects or functions with external linkage, addresses of objects and functions and pointer to members.
i think the template should recieve const variable.
so I think this is wrong.
	double val = 5.0;   // should be const double val = 5.0;	cout << SineVal(val) << endl;

as far as i remember, template is generate on compile time. and if you don't use const variable, then it will compile error.
I think metaprogramming is not used for run time calculation, instead it is used for defining constants.
Quote:Original post by EkEk
i think the template should recieve const variable.
so I think this is wrong.
*** Source Snippet Removed ***
as far as i remember, template is generate on compile time. and if you don't use const variable, then it will compile error.
I think metaprogramming is not used for run time calculation, instead it is used for defining constants.


Just got done with that, thanks! However, I'm getting the same errors.

Here's the updated source:

#include <iostream>#include <tchar.h>#include <cmath>#pragma inline_depth(255)#pragma inline_recursion(on)using namespace std;template<double& R> struct Sine{	enum { MaxTerms = 10 };	static inline double sin()	{		return R * Series<R, 0, MaxTerms>::val();	}};template <double& R, int I, int MaxTerms> struct Series{	enum	{		Continue = I + 1 != MaxTerms,		NxtI = ( I + 1 ) * Continue,		NxtMaxTerms = MaxTerms * Continue	};	static inline double val()	{		return 1 - R*R/(2.0 * I + 2.0)/(2.0 * I + 3.0)*Series<R*Continue, NxtI, NxtMaxTerms>::val();	};};template <> struct Series<0.0, 0, 0>{	static inline double val() { return 1.0; };};#define SineVal( r ) Sine<r>::sin()int _tmain(int argc, _TCHAR* argv[]){	char ch;	cout << Sine<5.0>::sin() << endl;	cout << sin(5.0) << endl;	cin >> ch;	return 0;}


1>------ Build started: Project: CodeTester, Configuration: Debug Win32 ------1>Compiling...1>CodeTester.cpp1>f:\cross-platform object-oriented development engine\codetester\codetester.cpp(35) : error C2440: 'specialization' : cannot convert from 'double' to 'double &'1>f:\cross-platform object-oriented development engine\codetester\codetester.cpp(44) : error C2440: 'specialization' : cannot convert from 'double' to 'double &'1>f:\cross-platform object-oriented development engine\codetester\codetester.cpp(44) : error C2440: 'specialization' : cannot convert from 'int' to 'double &'1>        f:\cross-platform object-oriented development engine\codetester\codetester.cpp(44) : see reference to class template instantiation 'Sine<R>' being compiled1>        with1>        [1>            R=01>        ]1>f:\cross-platform object-oriented development engine\codetester\codetester.cpp(44) : error C2973: 'Sine' : invalid template argument 'int'1>        f:\cross-platform object-oriented development engine\codetester\codetester.cpp(17) : see declaration of 'Sine'1>Build log was saved at "file://f:\Cross-Platform Object-Oriented Development Engine\CodeTester\Debug\BuildLog.htm"1>CodeTester - 4 error(s), 0 warning(s)========== Build: 0 succeeded, 1 failed, 13 up-to-date, 0 skipped ==========


Thanks,
exorcist_bob
Reference non-type template paramters must be bound to variables with external linkage. 5.0 is a double literal, which is not a variable with external linkage.
double five = 5.0;int _tmain(int argc, _TCHAR* argv[]){  // blah blah blah  cout << Sine<five>::sin() << endl;  // blah blah blah
I'm confused as to why you aren't just writing a function.

CM

This topic is closed to new replies.

Advertisement