When I try to use float
as a template parameter, the compiler cries for this code, while int
works fine.
Is it because I cannot use float
as a template parameter?
#include<iostream>
using namespace std;
template <class T, T defaultValue>
class GenericClass
{
private:
T value;
public:
GenericClass()
{
value = defaultValue;
}
T returnVal()
{
return value;
}
};
int main()
{
GenericClass <int, 10> gcInteger;
GenericClass < float, 4.6f> gcFlaot;
cout << "\n sum of integer is "<<gcInteger.returnVal();
cout << "\n sum of float is "<<gcFlaot.returnVal();
return 0;
}
Error:
main.cpp: In function `int main()':
main.cpp:25: error: `float' is not a valid type for a template constant parameter
main.cpp:25: error: invalid type in declaration before ';' token
main.cpp:28: error: request for member `returnVal' in `gcFlaot',
which is of non-class type `int'
I am reading "Data Structures for Game Programmers" by Ron Penton, the author passes a float
, but when I try it it doesn't seem to compile.
Indeed, you can't use float literals as template parameters. See section 14.1 ("A non-type template-parameter shall have one of the following (optionally cv-qualified) types...") of the standard.
You can use a reference to the float as a template parameter:
If you only want to represent a fixed precision, then you can use a technique like this to convert a float parameter into an int.
For example an array with a growth factor of 1.75 could be created as follows assuming 2 digits of precision (divide by 100).
If you dont like the representation of 1.75 as 175 in the template argument list then you could always wrap it in some macro.
You can always fake it...
Ref: http://code-slim-jim.blogspot.jp/2013/06/c11-no-floats-in-templates-wtf.html
Wrap the parameter(s) in their own class as constexprs. Effectively this is similar to a trait as it parameterizes the class with a set of floats.
and then create a template taking the class type as a parameter
and then use it like so...
This allows the compiler to guarantee that only a single instance of the code is created for each template instantiation with the same parameter pack. That gets around all the issues and you are able to use floats and doubles as constexpr inside the templated class.
If you are ok to have a fixed default per type you can create a type to define it as a constant and specialize it as needed.
If you have C++11 you can use constexpr when defining the default value. With C++14, MyTypeDefault can be a template variable which is a bit cleaner syntactically.
Just to provide one of the reasons why this is a limitation (in the current standard at least).
When matching template specializations, the compiler matches the template arguments, including non-type arguments.
By their very nature, floating point values are not exact and their implementation is not specified by the C++ standard. As a result, it is difficult to decide when two floating point non type arguments really match:
These expressions do not necessarily produce the same "bit pattern" and so it would not be possible to guarantee that they used the same specialization - without special wording to cover this.