0

I am reviewing some code I downloaded, and I see the following:

class MyClass
{
[...]
    public:
        static double shape;
[...]
};
double MyClass::shape = 1.0;

It seems strange that the type is declared twice. Why is this necessary?

bernie
  • 546
  • 3
  • 13
  • Because `static double shape = 1.0;` doesn't compile? – Oliver Charlesworth Feb 01 '18 at 19:46
  • 1
    The type is declared only once (static double MyClass::shape, in the class declaration). The initial value of the static class member is *defined* in the statement double MyClass::shape = 1.0;. See also: https://stackoverflow.com/questions/1410563/what-is-the-difference-between-a-definition-and-a-declaration – cli_hlt Feb 01 '18 at 19:46

1 Answers1

4

The declaration in the class definition, is a pure declaration.

The declaration after the class definition, is a definition. It allocates storage for the variable.

One reason to do it that way is that for static data members only those of integral or enum types, or constexpr, or C++17 inline, can be initialized in the in-class declaration.


A definition like the above should not be placed in a header file, because if that header is included in more than one translation the multiple definitions will violate the One Definition Rule.

One simple solution is to replace the direct static variable with an accessor function:

// OK to place in a header:

class MyClass
{
public:
    static auto shape()
        -> double&
    {
        static double the_shape = 1.0;
        return the_shape;
    }
};
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • and in my experience the primary reason the two are separated is because you (generally) only want the variable stored (defined) *once*, but often want it declared for multiple source files. So declarations will exist in header files (that are included in multiple source files), and the definition will exist in just one source file. (as the answer now says...I'll leave this comment here in case the wording difference clarifies for anyone) – zzxyz Feb 01 '18 at 19:51
  • @zzxyz: I added a little discussion about that, showing how to do it for a header-only module. There's also the templated struct trick for that (the ODR has a special exemption for templates). And with C++17 we have `inline` variables, but I'm not sure about current compiler support for that. – Cheers and hth. - Alf Feb 01 '18 at 19:54
  • Yeah, glad there's new ways to do it. The old method is...painful, in addition to being non-intuitive for those learning the language. – zzxyz Feb 01 '18 at 19:57
  • Ok i see. It is in fact the case that the declaration and definition exist in a single `.h` file here. I now understand that this would cause problems if this file were included by more than one source file (which isn't the case). – bernie Feb 01 '18 at 20:03
  • @bernie: Note that the currently selected "solution" of the duplicate, has some incorrect claims. But also one correct subtlety, that in-class initialization is also OK for enumerated type, which in the standard is not regarded as an integral type. Fixed this answer accordingly. – Cheers and hth. - Alf Feb 01 '18 at 20:18