4

I have this question bugging me.

Why cant I have code like this in my .hpp file.

class H {
  private:
    static const int i =5;
    static const float f = 1.0;
    static const string s = "string";
}

Only int, bool, enum and constexpr etc can be declared and initialized like that.

My questions:

  1. Why do strings and other complex datatypes needs proper initialization in cpp? They are constant.

  2. Why do we have different behavior for floats and ints? my guess:gcc does not support that, but can be supported easily if we use constexpr.

v78
  • 2,803
  • 21
  • 44
  • Integral type have always had a special rule allowing this. Other types have now got [inline variables](https://stackoverflow.com/questions/38043442/how-do-inline-variables-work) in C++17. – Bo Persson May 30 '18 at 09:20

1 Answers1

2

It's because the standard says so.

Normally, the out-of-line definition rule applies to static const members:

The declaration of a static data member in its class definition is not a definition.

The only exception is that since C++11 integral and enum static const types can be initialized in-line.

See [class.static.data]/3 (emphasis mine):

If a non-volatile const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression.

As Bjarne mentioned:

So why do these inconvenient restrictions exist? A class is typically declared in a header file and a header file is typically included into many translation units. However, to avoid complicated linker rules, C++ requires that every object has a unique definition. That rule would be broken if C++ allowed in-class definition of entities that needed to be stored in memory as objects.

The rational could have been that integral types become compile-time constants, although I tend to disagree because the rule of a single address across compilation units still applies, which means the compiler must still emit the static const members with weak linkage and have the linker fold them, just like it does with multiply defined templates. At which point the restriction on integral types becomes moot since the same folding can be applied to any type. In fact, C++17 "fixes" it with inline members:

class H {
private:
    inline static const int i = 5;
    inline static const float f = 1.0;
    inline static const string s = "string";
};
rustyx
  • 80,671
  • 25
  • 200
  • 267