静态数据成员模板专用化的实例化点在哪里

where's the point of instantiation of static data member template specialization

本文关键字:实例化 在哪里 专用 数据成员 静态      更新时间:2023-10-16

考虑以下代码:

#include <iostream>
template<typename T>
struct Test{
template<typename U>
static U value;
};
template<typename T>
template<typename U>
U Test<T>::value = U{};
//#1
int main(){
auto d = Test<int>::value<int>;
}
//#2

标准中的[温度点]部分涵盖了实例化点的大部分情况。然而,我认为静态数据成员模板还不清楚,原因是:

温度点#1

对于函数-模板专门化、成员-函数-模板专业化或类模板的成员函数或静态数据成员的专门化,如果该专门化是隐式实例化的,因为它是从另一个模板专门化中引用的,并且从中引用它的上下文取决于模板参数,专业化的实例化点就是封闭专业化的实例点。否则,此类专门化的实例化点紧跟在引用该专门化的命名空间范围声明或定义之后。

温度点#4

对于类模板专门化、类成员模板专门化或类模板的类成员的专门化,如果该专门化是隐式实例化的,因为它是从另一个模板专门化中引用的,如果引用该专门化的上下文取决于模板参数,并且如果所述专门化在所述封闭模板的实例化之前没有被实例化,则所述实例化点紧接在所述包围模板的实例化点之前。否则,此类专门化的实例化点直接位于引用该专门化的命名空间范围声明或定义之前。

两段分别涵盖了他们提到的情况,它们是a specialization for static data member of a class templatea class member template specialization。因此,静态数据成员模板的专用化可以称为a specialization for static data member of a class templatea class member template specialization?我更喜欢将其视为类成员模板专业化,我的原因是在第一段中,它提到了成员函数模板专业化[/strong>,这意味着如果a是X模板的专业化,它会称其为X模板专业化,但这只是我的推断。

在[temp.static]部分中,这意味着静态数据成员和静态数据成员模板统称为类或类模板的静态数据成员。

静态温度#1

静态数据成员或静态数据成员模板的定义可以在包含静态成员的类模板的定义的命名空间范围中提供。

[注意:静态数据成员模板的专用化是静态数据成员。成员函数模板的专用性是成员函数。成员类模板的专用是嵌套类。—尾注]

现在,措辞使问题更加不清楚。根据以上规则,Test<int>::value<int>的实例化点是在#2还是在#1

如果Test<int>::value<int>的POI在#2,那么它会被认为是a specialization for static data member of a class template,否则如果它在#1,那么它就会被认为是a class member template specialization,我不知道哪个位置是正确的。如果我错过了什么,请纠正我。

您可能会混淆实例化/专业化

template<typename T>
template<typename U>
U Test< T >::value = 88;  // <- this is not specialization 
template<>
template<>
int Test< int >::value<int> = 98;  // <- this is specialization

运行此代码https://godbolt.org/z/h434eG,查看输出中数字的顺序,然后用特殊化取消对块的注释,然后再次运行。

Cleiton Santoia Silva的观点是没有明确的成员模板专业化。但如果你读了温度指令#3:

除非类模板或成员模板的成员已显式实例化或显式专用化,否则当在需要成员定义存在的上下文中引用专用化时,成员的专用化被隐式实例化;特别地,静态数据成员的初始化(以及任何相关的副作用)不会发生,除非静态数据成员本身以需要静态数据成员定义存在的方式使用。

我们仍然会得到一个由主要模板使用触发的专门化

我会对";虚拟专业化";,因为它在代码中不可见但问题是编译器将在哪里编写这种专门化——它在[temp.point]中定义。但由哪一段定义?如果你仔细阅读第4段,你可以看到它有一个附加条件(否则与内部/秒If有关):

。。。如果专门化是隐式实例化的,因为它是从另一个模板专门化中引用,如果专门化是的上下文

是类模板"引用的成员函数模板;测试"?不,它只在main内部引用。所以,我们不需要看这一段。

但让我们看看第一段。在那里,我们有几乎相同的条件,只是没有";如果";但是";以及":

对于函数-模板专门化、成员-函数-模板专业化或类模板的成员-函数或静态数据成员的专门化,如果该专门化是隐式实例化的,因为它是从另一个模板专门化中引用的的上下文

因为条件不成立;其他情况":

。。。否则,此类专门化的实例化点紧跟在引用专门化的命名空间范围声明或定义之后。

这句话在某种程度上具有误导性。什么是命名空间范围声明(我在标准中找不到定义)?这里的定义是什么?你的解释是,这个定义是指模板出现的地方(主要)。但我不这么认为。我认为模板的定义是有意义的。

因此,要回答您的问题:它应该在main之前(在main之后会使程序"格式错误")。但你是对的,措辞应该有所改进。

Btw:你可以有一个";在C++编译器内部查找";通过使用cppnights(此处)。不幸的是,对于隐式全局命名空间范围,它似乎不能正确工作(在这种情况下)。在这里你可以看到专业化的地方;实际上";实例化。


旧答案

克莱顿·桑托亚·席尔瓦是完全正确的。您的源代码只显示了一个静态模板成员声明和一个静态的模板成员定义。这不是专门化。

看这里

模板安装发生在这里:

#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