这里有一个类似的问题,但它与带有typename
关键字的模板有关。
给定一个模板:
template < int X, char Y >
struct foo
{
char myArray[ X <= 0 ? 1 : X ];
static const char Z = Y;
}
该静态成员会在所有实例之间共享,foo
还是编译器会看到模板已使用不同的参数调用并创建新类型?
分配在那里的静态常量成员根据模板参数传递的值而变化。将其缩短为如下所示:
template<int X>
struct foo {
static const int value = X;
};
你不会期望foo<10>::value
和foo<11>::value
你一样吧?这通常用于模板元编程,因为该静态常量的值取决于模板参数。
实际上,您定义的模板参数是非类型参数,与其他两种模板参数不同:类型参数和模板参数。
但是,它们仍然是模板参数,对于每组不同的模板参数,您将获得一个全新的数据类型。例如,foo<3,'a'>
是与 不同的数据类型foo<4,'a'>
,又与 不同foo<3,'b'>
,依此类推。
因此,静态成员也为模板参数的每个选择单独分配和初始化。
在这方面,非类型参数、类型参数和模板参数都以相同的方式工作。
作为参考,来自标准(C++11):
(§14.7/6)从模板实例化的每个类模板特化都有自己的任何静态成员的副本。[ 例子:
template<class T> class X { static T s; }; template<class T> T X<T>::s = 0; X<int> aa; X<char*> bb;
X<int>
有一个s
类型的静态成员int
,并且X<char*>
有一个s
类型的静态成员char*
。—结束示例]
上面标准给出的例子是指类型参数,但第 14.7/6 节是模板一般讨论的一部分。更广泛的上下文清楚地表明,这适用于使用非类型参数(或类型、非类型和模板参数的组合)的模板。
还有一个关于模板实例化的类型等效的部分,它解释了在什么情况下具有非类型参数的模板实例化被认为是相等的(我强调的相关部分):
(§14/1)两个模板 ID 引用相同的类或函数,如果
——它们的模板名称、操作符函数 ID 或文字操作符 ID 引用相同的模板并且
——它们对应的类型模板参数是相同的类型和
——它们对应的整数或枚举类型的非类型模板参数具有相同的值,并且
——它们对应的指针类型的非类型模板参数引用相同的外部对象或函数,或者都是空指针值和
——它们对应的指针成员类型的非类型模板参数引用同一个类成员,或者都是空成员指针值和
— 它们对应的引用类型的非类型模板参数引用相同的外部对象或函数,并且
— 它们对应的模板模板参数引用相同的模板。
放在上下文中,这意味着同一类模板的两个实例构成两个不同的数据类型,即使它们仅在一个非类型参数的值上有所不同。