web-dev-qa-db-ja.com

クラスの静的変数の初期化順序

2つの静的変数を持つクラス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;
}

出力は200です。だから、誰が私に理由を教えてもらえますか?

61
QuantumPlus

ルックアップルールによればそれは正しいです。 [basic.lookup.unqual]/1 言います:

クラスXの静的データメンバーの定義で使用される名前(静的メンバーの限定IDの後)は、Xのメンバー関数で名前が使用されたかのように検索されます。[注:[class.static.data ]は、静的データメンバーの定義での名前の使用に関する制限についてさらに説明します。 —メモを終了]

修飾されていないaが検索されるためas ifあなたはメンバー関数の中にいるので、最初にメンバーA::aを見つけなければなりません。 A::aA::bの初期化順序はルックアップに影響しませんが、結果の定義の精度に影響します。

36
StoryTeller

だから、誰も私に理由を教えてもらえますか?

これは basic.scope.class/4 に明記されています。

クラス定義の終わりまで、またはそれを超えて宣言されている可能性のあるスコープは、リージョンにも拡張されますメンバーが字句的にクラス外で定義されていても(このには静的データが含まれます)メンバー定義、ネストされたクラス定義、およびメンバー関数の定義を含み、メンバー関数本体と、declarator-idに続くそのような定義の宣言子部分の任意の部分(パラメーター宣言節を含む)およびデフォルトの引数)。

したがって、あなたが持っているとき

int A::a = 200;
int a = 100;
int A::b = a; // note the '::' scope resolution operator
              // OUTPUT: 200

aは実際にA::aを参照します。これは、クラススコープextendedであるためです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

aは(グローバル)::aを参照します。ここでbclass Aのメンバーではないため、
i.eクラススコープ拡張はありません。

16
Joseph D.

c ++ draft/class.static

メンバーのdeclarator-idおよび名前に続く静的メンバーの定義でunqualified-idが使用されている場合lookup([basic.lookup.unqual])は、unqualified-idがメンバーのクラス(またはメンバーのクラスの基本クラス)の静的メンバー、列挙子、またはネストされた型を参照していることを検出します。 )、unqualified-idはqualified-id式に変換されます、nested-name-specifierはメンバーが参照されるクラススコープを指定します。 [注意:非静的データメンバーおよび非静的メンバー関数の使用に関する制限については、[expr.prim.id]を参照してください。 —メモを終了]

それはあなたの状況でunqualified-idがqualified-id式に変換されると言います。

int A::b = a;

修飾IDを設定できますが、このようなネストされた名前指定子はありません。

int A::b = ::a;
8
dao leno

名前の検索により、aA::aとして解決されるためです。これを行うには、スコープを手動で解決する必要があります。

int A::b = ::a;
        // ^ Global scope resolution

実例

6