Cleiton Santoia Silva 的重点是没有明确的成员模板专业化。
但是,如果您阅读 temp.inst#3:
除非类模板或成员模板的成员被显式实例化或显式特化,成员的特化在特化时被隐式实例化在需要成员定义存在的上下文中引用;特别是,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非该静态数据成员本身的使用方式要求该静态数据成员的定义存在。
我们仍然得到一个由 main 中的模板使用触发的特化。 我会说“虚拟专业化”,因为它在代码中是不可见的。这会导致完全就像有明确的专业化一样。
但问题是编译器会在哪里编写这个专业化 - 它在 [temp.point] 中定义。但在哪一段?如果你仔细阅读第4段你可以看到它有一个额外的条件(否则与inner / second if有关):
...如果特化是隐式实例化的,因为它是
从另一个模板特化中引用,如果是特化所在的上下文
类模板“Test”是否引用了成员函数模板?不,它只在 main 中引用。所以,我们不需要看这一段。
但是让我们看看第一段。那里我们有几乎相同的条件,只是没有“if”而是“and”:
对于函数模板特化、成员函数模板特化或类模板的成员函数或静态数据成员的特化,如果特化是隐式实例化的,因为它是从另一个模板特化中引用的并且上下文来自
因为条件不成立,我们需要看一下“else case”:
...否则,这种特化的实例化点紧跟在引用特化的命名空间范围声明或定义之后。
这句话在某种程度上具有误导性。什么是命名空间范围声明(我在标准中没有找到定义)?这里的定义是什么?您的解释是该定义是指模板实例化发生的位置(主要)。但我不这么认为。我认为模板的定义是有意义的。
所以回答你的问题:它应该在 main 之前(在 main 之后会使程序“格式错误”)。但你是对的,应该改进那里的措辞。
顺便说一句:
您可以使用 cppinsights (here) “查看 C++ 编译器内部”。不幸的是,对于隐式全局命名空间范围,它似乎无法正常工作(在这种情况下)。在这里,您可以看到“实际”实例化的特化。
旧答案
克莱顿·桑托亚·席尔瓦是完全正确的。您的源代码仅显示一个静态模板成员声明和一个静态模板成员定义。这不是专业。
看here
模板安装发生在这里:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
int main()
{
auto d = Test<int> //<- here is Test<int> implicitly instantiated
::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
如果你写这个 - 你的程序会变得不正确:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition
int main()
{
auto d = Test<int> //<- here is Test<int> instantiated
::value<int>; //<- here is the member template instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
不过这样就好了。非内联静态成员定义必须在 cpp 文件中定义,以免违反 ODR。
但与所有模板一样 - 每个模板定义都必须在所有翻译单元中可用。这就是为什么这样的定义通常在标题中定义的原因:
#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value; //this is a static member template declaration
};
//this is a partial specialization of a template member variable
template<>
template<typename U>
U Test<char>::value = 42;
//this is a full specialization of a template member variable
template<>
template<>
int Test<int>::value<int> = 22;
int main()
{
auto d = Test<int> //<- here is Test<int> implicitly instantiated
::value<int>; //<- here is the member template ::Test<int>::value<int> implicitly instantiated
std::cout << Test<char>::value<int> << "\n"; //this prints 42
std::cout << Test<int>::value<int> << "\n"; //this prints 22
std::cout << Test<bool>::value<bool> << "\n"; //this prints 0
}
template<typename T>
template<typename U>
U Test<T>::value = U{}; //this is a static member template definition