C++模板如何支持非静态非类型参数?C++20实例化疑问解析
为什么C++20允许用非静态对象实例化模板?
C模板确实是编译期构造的,但C20对**非类型模板参数(NTTP)**的规则做了大幅扩展,打破了之前只能用静态存储期常量的限制。
在C20之前,非类型模板参数只能是基本类型、指向静态对象的指针/引用、枚举这类简单类型。但C20引入了**结构类型(structural type)**作为NTTP的合法类型——简单说,只要一个类型是聚合类型、没有用户定义的构造/析构/赋值函数、没有虚函数,且所有成员都是结构类型或基本类型,它就是结构类型(比如示例里的struct X {}就完全符合)。
对于结构类型的NTTP,C++20允许传递自动存储期(也就是非静态)的对象,前提是这个对象的初始化表达式是常量表达式,而且它的所有成员值在编译期是可确定的。编译器会在编译期把这个对象的逐成员值拷贝下来,作为模板实例的一部分——本质上还是编译期完成构造,只是允许用自动存储期的对象来提供编译期已知的值而已。
如何设置非静态非类型模板参数?
结合你的代码示例,分三步来做:
定义符合要求的参数类型
你的自定义类型必须是C++20认可的结构类型。比如示例里的struct X {}:它是聚合类型,没有自定义的特殊成员函数,也没有虚函数,完全满足结构类型的要求。如果你的类型有自定义构造函数或者虚函数,就没法用来做非类型模板参数。声明模板时指定非类型参数
在模板参数列表里直接声明类型和参数名就行,像示例里这样:template<typename T, X x> auto f() { return x; }这里的
X x就是一个非类型模板参数,类型是我们自定义的结构类型X。实例化时传递非静态对象
只要传递的非静态对象是用常量表达式初始化的,就能作为模板实参。比如示例里的main函数:int main() { auto x = X{}; // X{}是常量表达式,x的所有值编译期都能确定 f<double, x>(); // 合法,编译器会把x的编译期值传入模板实例 }注意:如果你的对象是用运行时才能确定的值初始化的(比如
X x{some_runtime_variable}),那肯定不能作为NTTP,毕竟模板实例化必须在编译期完成。
内容的提问来源于stack exchange,提问作者cmutex

