理解非类型模板参数
understanding of non-type template parameters
我理解以下段落Per c++ 11 Standard N3485 Section 14.1.7有问题。我认为理解基本原理比记忆事实更重要。
非类型模板形参不能声明为浮点型、类型或void型。
[示例:template<double d> class X; // error template<double* pd> class Y; // OK template<double& rd> class Z; // OK
-end example]
我对这个规则有一些疑问:
-
是否有
floating point
类型不能作为模板参数的原因?这背后的原理是什么?我知道这在c++ 11之前是正确的,对于c++ 11标准来说似乎也是正确的。 -
为什么可以将
pointer
或reference
用于浮点类型作为非模板参数,而不是原始浮点类型?这里最大的区别是什么?
谢谢你的帮助。
为什么浮点类型不能用作模板形参?这背后的原理是什么?
虽然我不能给出最终的原因,但我可以肯定地想象,对接受浮点指针值作为参数的模板进行专门化会出现问题。
浮点数之间的相等比较是很复杂的(从某种意义上说,它有时会给出意想不到的结果),当匹配特化时,编译器必须在提供的实参和模板被特化的值之间执行相等检查。
另一个类似的问题是确定相同类模板的两个实例是否实际上是相同的类型:
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
为同一类型,并且[…]
上面的例子表明,要确定同一个类模板的两个不同实例是否实际上是同一个类,需要在用作模板参数的常量表达式之间进行相等性检查。
要弄清楚这一点,请考虑整型和指针与它们的文字表示总是有一对一的关系。
然后让我们考虑一个非类型模板Foo<float>
。
假设它专为非二进制可表示的数字(如0.1
: Foo<0.1>
)而假设编译器根据专为符号名称进行修饰最终得到Foo_3DCCCCCC
这样的符号因为编译器对IEEE 754 32位代表使用"四舍五入"
但是我们假设这段代码的用户是这样编译的,编译器选择"四舍五入到正无穷"。然后,专门化的名称改为Foo_3DCCCCCD
,这是一个与之前在另一个翻译单元中专门化的函数完全不同的函数。
除非你开始制定各种各样的规则来处理所有这些事情(NaN、无穷大和其他非正常数字呢?),否则你就会让自己陷入不匹配和各种可能的问题。
- 扩展C++生成的代码的模板参数类型名称
- 如何在 c++ 中定义接受不同参数类型的函数向量?
- 在 C++ 中运行时调用模板时,是否可以切换模板的参数类型?
- 将函数参数类型声明为 auto
- 将函数的参数 - 签名从使用 'std::function<T>' 转换为模板参数类型
- 在 C++17 中调用具有不同参数类型的构造函数
- 具有先前参数类型匹配的参数包
- 我想知道为什么"std::unique_ptr<int> foo(新 int)"是合法的,因为"std::<int>unique_ptr"要求输入参数类型应该是"int"?
- 将可变参数类型列表的扩展打包为复杂类型的初始值设定项列表 - 合法吗?
- MSVC 错误:4 个重载中的任何一个都无法转换所有参数类型
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- 如何从第一个参数推断第二个参数类型?
- C++模板函数中,指定回调函子/lambda 的参数类型,同时仍允许内联?
- 如何用不同的参数类型和数字回调函数
- C++stoi:这两个重载都无法转换所有参数类型
- 为什么std::{container}::template不能推导其参数类型
- 为模板参数类型中的新对象分配内存
- 为指向成员模板参数的指针推导额外模板参数类型的紧凑方式
- 使用std::conditional中的模板来确定函数参数类型
- C++中的短参数类型