16
votes

In C++, static members may not be initialized in the class body with these exceptions:

  • static members of const integral type can be
  • static members of constexpr literal type must be

Can you explain why these exceptions?

Also, this holds:

Even if a const static data member is initialized in the class body, that member ordinarily should be defined outside the class definition.

This I never understood at all. What's the point of this extra definition?

Just trying to get some intuitions here.

1
The key point is whether or not the variable will be odr-used. As long as it isn't, you don't actually need to define it, since it suffices to paste its value whenever the variable is referred to.Kerrek SB
It's not an extra definition; it's a definition. Inside the class body you have a declaration.Pete Becker
As you might want to access the static data member from different translation units (= cpp files), you'll have to define a "location" where every translation unit refers to, i.e. a single translation unit where the static member is defined. It's the same thing as with (global) extern variables.dyp
@DyP: That's wrong. The linker must already cope with redundant definitions in the case of class templates. There is no difference here. There is no practical reason why the compiler cannot implicitly define each global variable and then simply merge them, as it is already required to do in numerous situations. The C++ Standard is (as usual) just making the user's life unnecessarily hard here.Puppy
@DeadMG Even if the the linker could do that, it's the same for extern variables IMO. You currently have to (according to the Standard) and I guess due to order of initialization, it's also useful.dyp

1 Answers

8
votes

Why can there be an initializer in the class definition?

Concerning the two exceptions for const and constexpr static data members:

[class.static.data]/3

[ Note: In both these cases, the member may appear in constant expressions. — end note ]

I.e. with an initializer, you may use them in constant expressions, e.g.

struct s
{
    static std::size_t const len = 10;
    int arr[len];
};
std::size_t const s::len;

If len wasn't initialized in the class definition, the compiler couldn't easily know its value in the next line to define the length of arr.

One could argue about allowing initializers for of non-const, non-constexpr static data members in the class definition, but this could interfere with the initialization order:

[basic.start.init]/2

Definitions of explicitly specialized class template static data members have ordered initialization. Other class template static data members (i.e., implicitly or explicitly instantiated specializations) have unordered initialization. Other non-local variables with static storage duration have ordered initialization.

That is, the order of the definitions including initializers is important. The order of (dynamic) initialization of non-local objects is only defined within a translation unit, this is another reason why there has to be a definition including initializer for non-const, non-constexpr static data members.


What's the point of this extra definition?

This has already been answered in the comments IMO. You might want to add the ODR, that is, as a name with external linkage, the static data member must (only) be defined in one translation unit (if it's ODR-used). It's up to the programmer to choose this translation unit.