模板非静态数据成员初始化程序何时实例化

When are template non-static data member initialisers instantiated?

本文关键字:程序 何时 实例化 初始化 数据成员 静态      更新时间:2023-10-16

这里有一个简短的自包含测试用例来解释我的问题。GCC接受此代码,但clang和Intel拒绝:

template <typename T>
struct false_t {
static const bool value = false;
};
template <typename T>
int f() {
static_assert(false_t<T>::value, "");
return 0;
}
template <typename T>
struct S {
int m = f<T>();
};
int s = sizeof(S<int>);

或者,根据pmr的评论,这里有一个更简单的例子,它也被gcc接受,并被clang拒绝:

struct S;
template <typename T> struct X { int x = T(); };
int s = sizeof(X<S>);

sizeof(S<int>)(或sizeof(X<S>))应该实例化它所需要的类的位,但编译器在这些位的具体位置上存在分歧。由于非静态数据成员初始值设定项只能由构造函数使用,GCC执行实例化是实例化类构造函数的一部分。clang和英特尔早就这么做了。

我很难理解标准在[ptemp.inst]p1:中说了什么

类模板专门化的隐式实例化导致类成员函数、成员类、作用域成员枚举、静态数据成员和成员模板的声明的实例化,而不是定义或默认参数的实例化;它导致了无范围成员枚举和成员匿名联合定义的隐式实例化。

因为我根本看不到非静态数据成员(带或不带初始化程序)的声明在哪里被实例化。

关于我在哪里遇到这种情况的更多细节:我试图创建一个模板助手类(在运行时永远不会创建),其中包含一个使用std::declval<T>()初始化的成员(我应该补充一点,我现在意识到这无论如何都没有多大用处),而libstdc++对std::declval的实现包含一个静态断言,就像我的示例中那样。通过避免std::declval,我可以毫不费力地解决这个问题,但我想知道标准需要什么。

在试图弄清楚如何问这个问题时,我偶然发现了答案,但我认为无论如何发布都可能有用。

这是C++标准的公开问题之一,确切地说是1396号。其目的是初始化程序只在需要时被实例化:

非静态数据成员初始值设定项与成员函数和默认参数获得相同的后期解析,但它们是否也像它们一样根据需要实例化?什么时候检查它们的有效性?

2012年10月会议纪要:

CWG同意非静态数据成员初始值设定项应该像默认参数一样处理。

但这种方法仍有许多问题有待解决。在它们被解决之前,不同的编译器在不同的时间执行实例化是很自然的,需要特定行为的代码应该被重写以避免这样的要求。在我的情况下,这意味着不使用std::declval