Class static variable initialization order

C++ScopeLanguage Lawyer

C++ Problem Overview


I have a class A which has two static variables. I'd like to initialize one with another, unrelated static variable, just like this:

#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;
}

The output is 200. So, could anyone tell me why?

C++ Solutions


Solution 1 - C++

That's correct according to the lookup rules. [basic.lookup.unqual]/13 says:

> A name used in the definition of a static data member of class X > (after the qualified-id of the static member) is looked up as if the > name was used in a member function of X. [ Note: [class.static.data] > further describes the restrictions on the use of names in the > definition of a static data member.  — end note ]

Since the unqualified a is looked up as if you are inside a member function, it must find the member A::a first. The initialization order of A::a and A::b doesn't affect the lookup, though it affects how well defined the result is.

Solution 2 - C++

> So, could anyone tell me why?

This is clearly stated in basic.scope.class/4, emphasis mine:

> The potential scope of a declaration that extends to or past the end > of a class definition also extends to the regions defined by its > member definitions, even if the members are defined lexically outside > the class (this includes static data member definitions, nested class > definitions, and member function definitions, including the member > function body and any portion of the declarator part of such > definitions which follows the declarator-id, including a > parameter-declaration-clause and any default arguments).

Thus, when you have

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

a actually refers to A::a because the class scope is extended by A::b.

Unlike if you have:

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 would refer to the (global) ::a since b here is not a member of class A,
i.e. no class scope extension.

Solution 3 - C++

c++draft/class.static

> If an unqualified-id is used in the definition of a static member following the member's declarator-id, and name lookup ([basic.lookup.unqual]) finds that the unqualified-id refers to a static member, enumerator, or nested type of the member's class (or of a base class of the member's class), the unqualified-id is transformed into a qualified-id expression in which the nested-name-specifier names the class scope from which the member is referenced. [ Note: See [expr.prim.id] for restrictions on the use of non-static data members and non-static member functions. — end note ]

It says the unqualified-id is transformed into a qualified-id expression in your situation.

int A::b = a;

You can set qualified-id but has no nested-name-specifier like this.

int A::b = ::a;

Solution 4 - C++

Because the name look up resolves the a as A::a. If you want to do this you will need to resolve the scope manually:

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

Live Example

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionQuantumPlusView Question on Stackoverflow
Solution 1 - C++StoryTeller - Unslander MonicaView Answer on Stackoverflow
Solution 2 - C++Joseph D.View Answer on Stackoverflow
Solution 3 - C++dao lenoView Answer on Stackoverflow
Solution 4 - C++Fantastic Mr FoxView Answer on Stackoverflow