5

如果表达式的类型不依赖,但我们使用它来初始化静态自动变量,会发生什么?GCC 和 Clang 的行为不同

template<typename T>
struct A {
   static inline auto x = sizeof(T{}.f);
};

A<int> a;

GCC 不会引发错误。但是 Clang 认为这是无效的,因为它实例化了“sizeof”的操作数。GCC 似乎跳过了该步骤,因为它sizeof(T{}.f)总是具有类型size_t(不依赖于类型),因此它已经知道类型,x而无需实例化。如果我们引用 ,则两个编译器都会一致地拒绝该程序x,例如通过(void) a.x;

它甚至必须解决类型x吗?如果我没记错的话,对于 C++14 及更高版本,该语言允许使用“占位符类型”来保存事物(如函数)并进行延迟实例化,以便稍后找出实际的返回类型。它是否也必须应用它x,所以x在我们提到之前保持占位符类型a.x

根据标准,哪个编译器是正确的?


编辑

有人问

嗯,这不应该等同于这个吗?

template<typename T>
struct A {
   static const std::size_t x;
};

template<typename T>
inline constexpr std::size_t A<T>::x = sizeof(T{}.f);

不同之处以及我在问题中关心的是,我的问题中的静态数据成员是auto. 因此,为了知道 的类型x,您需要知道初始化程序的类型。Clang 似乎急切地实例化初始化程序以获取类型。但显然 GCC 没有?我想了解发生了什么。

4

1 回答 1

2

[temp.inst]/3

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

简单的写法A<int> a;不会A<int>::x以需要其定义存在的方式使用,因此不应发生其初始化。gcc 是正确的。

于 2017-11-10T20:24:39.197 回答