内联静态自动的初始化程序“sizeof(T)”...是不是需要实例化?

Posted

技术标签:

【中文标题】内联静态自动的初始化程序“sizeof(T)”...是不是需要实例化?【英文标题】:Initializer "sizeof(T)" of inline static auto... Does it need instantiation?内联静态自动的初始化程序“sizeof(T)”...是否需要实例化? 【发布时间】:2017-11-09 08:10:47 【问题描述】:

如果表达式的类型不依赖,但我们使用它来初始化静态自动变量,会发生什么? 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 没有?我想了解发生了什么。

【问题讨论】:

不是任何想象的规范性参考。但众所周知,GCC 有时会跳过步骤,所以我不会感到惊讶。 呃,这不应该等同于this 吗?这在两个编译器中都可以编译(但请参阅注释) PS:问题标题说“constexpr inline”,但代码示例没有... @MassimilianoJanes 更新 【参考方案1】:

来自[temp.inst]/3:

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

简单地编写A&lt;int&gt; a; 并不会以要求其定义存在的方式使用A&lt;int&gt;::x,因此不应发生其初始化。 gcc 是正确的。

【讨论】:

不确定我是否完全有信心。玩鬼倡导者:为什么不需要定义存在?我在命名空间范围内将它与inline auto x; 进行了比较,它抱怨“1::1:13:错误:使用推导类型'auto' 声明变量'x' 需要初始化器内联 auto x;”。所以看起来它需要初始化器,对于内联定义,它是定义的一部分。 @JohannesSchaub-litb 措辞似乎很清楚。根本没有使用成员。 不确定这里的“使用”是什么意思。当然,它在auto 的确定中被其自己的声明“使用”,可以声称。特别是,这里没有使用“odr-used”。 @JohannesSchaub-litb 如果这是真的,那么突出显示的子句将毫无意义。 @JohannesSchaub-litb 也许你是对的;确实 this 无法为 gcc 和 clang 编译,都实例化了静态成员

以上是关于内联静态自动的初始化程序“sizeof(T)”...是不是需要实例化?的主要内容,如果未能解决你的问题,请参考以下文章

C++ (P70—)

类定义中的静态数据成员初始化?

内联函数的局部静态/线程局部变量?

static的使用总结

Android - 为啥人们反复引用静态上下文内联,而不是在 Method() 中传递一次?

内联函数和静态内联函数之间的区别