What are the rules for initializing a static class variable?

I have legacy code and need to add a new class for post (which is irrelevant to my question). But it turns out that I need to declare an empty constructor in order for some static object to be initialized. Not a standard or compiler-supplied constructor, but an empty custom one. I tried to reduce the code to MWE and this is what I get:

#include <iostream>

using namespace std;

struct Test
{
    Test() {cout << "Test::Test()" << "\n";}
    void dummy(){}
};

template<typename T>
struct Message
{
    Message()
    {
        test.dummy(); // this call have to be here in order to initialize Test, but why?
    }

    static Test test;
};

template<typename T>
Test Message<T>::test;

struct A : public Message<A>
{
    //A(){} // uncomment this (and comment the default one) to call the Test constructor
    A() = default;
};

int main()
{
}

      

This is what happens:

  • The program itself is empty, i.e. no instances are created.
  • There's a CRTP for the class A

    , which seems to be critical for the example.
  • There is a static declaration for the base A

    and I expect it to be called by the constructor.
  • There's a dummy function call in there that doesn't do anything but is also critical.

The problem is, if I don't provide a custom constructor, then the static constructor will never get called. And I don't understand why I need it? What's the difference with default or compiler? And why do I need to call a dummy function?

I believe there is a rule for this. I tested it with different versions of gcc and clang - the behavior is the same. I really appreciate the links to the standard / documentation.

+3


source to share


2 answers


If you leave the A

default constructor and never call it, then there is no need to generate it and therefore no need to create test

. If you explicitly default to a definition, call the constructor, A

or access A::test

, it will be initialized correctly.

12.1 Constructors [class.ctor]

7 The default constructor, which is the default and not defined as remote, is implicitly defined when it is used by odr (3.2) to create an object of its class type (1.8), or when it is explicitly defaulted after its first declaration.



struct A : public Message<A>
{
    A() = default; // no constructor is emitted unless A is instantiated

    A(); // declaration
};

A::A() = default; // explicit default definition

int
main()
{
    A a; // instantiation
    A::test; // just explicitly access test so it is initialized regardless of A constructor
}

      

+4


source


C ++ 14 [temp.inst] / 2:

If a class template member or member template is not explicitly created or is not explicitly specialized, that member's specialization is implicitly created when the specialization is referenced in a context that requires the member to be defined; in particular, initialization (and any associated side effects) of a static data member does not occur unless the static data member itself is used in a way that requires the definition of a static data member.

This makes it clear that Message<A>::test

it will not initialize unless it is used so that its definition exists.

The only expression in your program that requires a definition must be test.dummy()

in the constructor Message<A>

; therefore, if this expression is removed, it test

should not be initialized.



In case it is present test.dummy()

, note that it is inside the template function, the constructor Message<A>

. If this constructor is never created, then test.dummy()

it will not be considered.

As pointed out by VTT, [class.ctor] says that an explicitly default constructor for A

means that the constructor is undefined when not used A

.

Your code does not use odr-use A

, so no constructor A

is defined, so there is no call to the base class constructor (this will only happen if a constructor was defined A

), so Message<A>()

no constructor template is created, so test

not required.

+3


source







All Articles