我可以对静态的,constexpr,类内初始化数据成员做什么?

And*_*owl 8 c++ static-members one-definition-rule constexpr c++11

这可能是有点不寻常的问题,因为它要求给一个简短的回答更充分的说明了另一个问题以及与之相关的C++标准11的某些方面.

为便于参考,我将在此总结引用的问题.OP定义了一个类:

struct Account 
{
    static constexpr int period = 30;
    void foo(const int &) { }
    void bar() { foo(period); } //no error?
};
Run Code Online (Sandbox Code Playgroud)

并且想知道为什么他没有得到关于他使用类内初始化静态数据成员的错误(一本书提到这是非法的).Johannes Schaub的回答指出:

  1. 这违反了一个定义规则 ;
  2. 无需诊断.

尽管我依赖这个答案的来源和有效性,但我真的不喜欢它,因为我个人觉得它太神秘了,所以我试图找出一个更有意义的答案,只取得部分成功.相关似乎是§9.4.2/ 4:

"有应是静态数据成员中的恰好一个定义ODR使用的程序中的(3.2); 没有诊断是必需的 " [重点是矿]

这让我更接近这一点.这就是§3.2/2定义了一个使用odr的变量:

"名称显示为潜在评估表达式的变量是odr-used,除非它是满足出现在常量表达式(5.19)中的要求的对象,并且立即应用左值到右值转换(4.1)" [重点是我的]

在OP的问题中,变量period显然满足出现在常量表达式中的要求,即constexpr变量.因此必须在第二个条件中找到原因:" 并立即应用左值到右值的转换(4.1) ".

这是我解释标准的麻烦.这第二个条件究竟意味着什么?它涵盖了哪些情况?这是否意味着如果从函数返回静态constexpr变量并非使用 odr(因此可以在类中初始化)?

更一般地说:你可以用静态constexpr变量做什么,这样你可以在课堂上初始化它?

Pup*_*ppy 3

这是否意味着静态 constexpr 变量如果从函数返回则不被 odr 使用(因此可以在类内初始化)?

是的。

本质上,只要你把它当作一个value,而不是一个object,那么它就不会被 odr 使用。考虑一下,如果您粘贴该值,代码将发挥相同的作用 - 这是当它被视为右值时。但在某些情况下却不会。

只有少数情况下不对原语执行左值到右值转换,即引用绑定,&obj可能还有其他一些情况,但这种情况很少。请记住,如果编译器为您提供了const int&对 的引用period,那么您必须能够获取它的地址,而且,每个 TU 的该地址必须相同。这意味着,在 C++ 可怕的 TU 系统中,必须有一个明确的定义。

如果不是 odr-used,编译器可以在每个 TU 中制作一个副本,或者替换该值,或者任何它想要的东西,并且您无法观察到差异。