类静态变量初始化顺序

Qua*_*lus 61 c++ scope language-lawyer

我有一个A类,它有两个静态变量.我想用另一个不相关的静态变量初始化一个,就像这样:

#include <iostream>
class A
{
public:
    static int a;
    static int b;
};

int A::a = 200;
int a = 100;
int A::b = a;
int main(int argc, char* argv[])
{
    std::cout << A::b << std::endl;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

输出是200.所以,谁能告诉我为什么?

Sto*_*ica 36

根据查找规则,这是正确的.[basic.lookup.unqual]/13说:

查找在类X的静态数据成员的定义中使用的名称(在静态成员的qualified-id之后),就好像该名称是在X的成员函数中使用一样.[注意:[class.static.data] ]进一步描述了静态数据成员定义中名称使用的限制. - 结束说明]

由于不合格a被查找,就好像你在成员函数中一样,它必须首先找到成员A::a.初始化顺序A::aA::b不影响查找,但它会影响结果的定义.

  • @Chiel - 我还想补充一点.这不是使这种含糊不清的规则.这些规则很好地消除了歧义.程序员选择了糟糕的名字使得这种模糊不清. (5认同)
  • 任何人都可以说出为什么行为这样决定的理由?我发现问题的代码非常令人困惑. (4认同)
  • @Bathsheba.但是就我所理解的而言,该规则使得模糊性而不是解决它. (2认同)
  • @Chiel - 名称查找必须从*某个范围*开始,这个只是一个合理的默认值.想象一下,我们的类中有一个"枚举类",我们想要使用它的一个枚举器来初始化静态成员.你更自然地写`A :: a = EnumClass :: THING;`而不是`A :: a = A :: EnumClass :: THING;`. (2认同)

Jos*_* D. 16

那么,谁能告诉我为什么?

这在basic.scope.class/4中明确说明,强调我的:

扩展到或超过类定义结尾的声明的潜在范围扩展到由其成员定义定义的区域,即使成员是在类之外的词法上定义(这包括静态数据成员定义,嵌套类定义,和成员函数定义,包括成员函数体和此类定义的声明器部分的任何部分,它们遵循declarator-id,包括parameter-declaration-clause和任何默认参数).

因此,当你有

int A::a = 200;
int a = 100;
int A::b = a; // note the '::' scope resolution operator
              // OUTPUT: 200
Run Code Online (Sandbox Code Playgroud)

a实际上是A::a因为类范围扩展A::b.

不像你有:

int A::a = 200;
int a = 100;
int b = a; // note b is not A::b
           // i.e. without the '::', scope resolution operator
           // OUTPUT: 100
Run Code Online (Sandbox Code Playgroud)

a会引用(全局),::a因为b这里不是成员class A,
即没有类范围扩展.


dao*_*eno 8

C++草案/ class.static

如果在成员的declarator-id之后的静态成员的定义中使用了unqualified-id,并且名称查找([basic.lookup.unqual])发现unqualified-id引用静态成员,枚举器或嵌套类型在成员类(或成员类的基类)中,将unqualified-id转换为qualified-id表达式,其中nested-name-specifier命名引用该成员的类作用域.[注意:有关使用非静态数据成员和非静态成员函数的限制,请参见[expr.prim.id]. - 结束说明]

它表示在您的情况下,unqualified-id会转换为qualified-id表达式.

int A::b = a;
Run Code Online (Sandbox Code Playgroud)

您可以设置qualified-id但没有像这样的嵌套名称说明符.

int A::b = ::a;
Run Code Online (Sandbox Code Playgroud)


Fan*_*Fox 6

因为名称查找解析了aas A::a.如果要执行此操作,则需要手动解决范围:

int A::b = ::a;
        // ^ Global scope resolution
Run Code Online (Sandbox Code Playgroud)

实例