浮点类型不能用作模板参数是否有原因?这背后的理由是什么?
虽然我无法给出最终原因,但我可以肯定地想象,专门接受一个浮点值作为参数的模板会出现问题。
浮点数之间的相等比较是棘手的(从某种意义上说,它有时会给出意想不到的结果),并且在匹配特化时,编译器必须在提供的参数和模板被特化的值之间执行相等检查。
另一个类似的问题是确定相同类模板的两个实例是否实际上是相同的类型:
template<double D>
struct X
{
// ...
};
int main()
{
X<3.0> x;
X<some_constant_expression()> y;
}
x
和y
实例是同一个类吗?3.0
为了决定这一点,必须在和之间执行相等性检查some_constant_expression()
。
为什么可以使用指针或对浮点类型的引用作为非模板参数,但不能使用原始浮点类型?
对于上述场景,关于指针的答案很简单:指针是整数值,指针之间的比较是明确定义的。
关于引用,有证据表明它们实际上被视为指针:
#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
}
此外,根据 C++11 标准的第 14.4/1 段:
两个模板 ID引用同一个类或函数,如果
— [...]
— 它们对应的整数或枚举类型的非类型模板参数具有相同的值,并且
— [...]
— 它们对应的引用类型的非类型模板参数引用相同的外部对象或函数,并且
— [...]
[示例:
template<class E, int size> class buffer { / ... / };
buffer<char,2*512> x;
buffer<char,1024> y;
声明x
和y
是同一类型,并且 [...]
上面表明,确定同一个类模板的两个不同实例是否实际上是同一个类需要在用作模板参数的常量表达式之间进行相等性检查。