Is there a reason that why floating point type cannot be used as template parameter? What is the rationale behind that?
While I cannot give the ultimate reason, I can definitely imagine there would be problems with specializing a template that accepts a floating pointer value as a parameter.
Equality comparisons between floating point numbers is tricky (in the sense that it sometimes gives unexpected results), and when matching specializations, the compiler would have to perform an equality check between the argument provided and the value for which a template is being specialized.
Another similar issue is determining whether two instances of the same class templates are actually the same type:
template<double D>
struct X
{
// ...
};
int main()
{
X<3.0> x;
X<some_constant_expression()> y;
}
Are x
and y
instances of the same class? To decide this, an equality check has to be performed between 3.0
and some_constant_expression()
.
Why it is OK to use pointer or reference to floating point types as non-template parameters, but not raw floating point type?
With respect to the above scenario, the answer concerning pointers is simple: pointers are integral values, and comparison between pointers is well defined.
Concerning references, evidence shows that they are in fact treated like pointers:
#include <type_traits>
double a = 0.0;
double b = 0.0;
template<double& D>
struct X : std::false_type { };
template<>
struct X<a> : std::true_type { }
int main()
{
static_assert(X<a>::value, "!"); // Does not fire
static_assert(X<b>::value, "!"); // Fires
}
Also, per paragraph 14.4/1 of the C++11 Standard:
Two template-ids refer to the same class or function if
— [...]
— their corresponding non-type template arguments of integral or enumeration type have identical values and
— [...]
— their corresponding non-type template-arguments of reference type refer to the same external object
or function and
— [...]
[ Example:
template<class E, int size> class buffer { / ... / };
buffer<char,2*512> x;
buffer<char,1024> y;
declares x
and y
to be of the same type, and [...]
The above shows that determining whether two different instances of the same class template are actually the same class requires an equality check between the constant expressions used as template arguments.