4

How does the following code exactly work?

#include <cstdio>

template<class T>
T x = T{};

void foo()
{
    class Test
    {
    public:
        Test() { std::printf("Test::Test\n"); }
    };

    Test t = x<Test>;
}


int main()
{
    std::printf("main\n");
}

Output

Test::Test
main

Live example

  • Why does it print Test::Test first instead of main?
  • Which standard it relies on? Is it C++1z only? I can't find the related proposal. Could you give me a link?
  • What is x in this code and how does Test t = x<Test> assignment actually work?

Moreover, if I change std::printf calls to std::cout the whole program crashes:

#include <iostream>

template<class T>
T x = T{};

void foo()
{
    class Test
    {
    public:
        Test() { std::cout << "Test::Test\n"; }
    };

    Test t = x<Test>;
}


int main()
{
    std::cout << "main\n";
}

Output

Segmentation fault      (core dumped) ./a.out

Live example

Why?

FrozenHeart
  • 19,844
  • 33
  • 126
  • 242

1 Answers1

3

As others have mentioned already, you used a variable template.

If I'm not mistaken, variable templates are analogous to something like this:

template<class T>
struct X {
    static T x;
};

template<class T>
T X<T>::x = T{};

You then use it, which would be something like:

void foo() {
    class Test {
    public:
        Test() { std::printf("Test::Test\n"); }
    };

    Test t = X<Test>::x;
}

If you try this, you will see the same result: coliru.

The template is instantiated in foo, and code to initialize the static member is emitted. This initialization happens before main runs, so you see Test::Test printed first.

As for the initialization happening despite the code where the variable is used never being called - I suppose the compiler could try to reason about foo never being called in the entire program, Test being a local class whose type does not escape foo, thus making the instantiation X<Test>::x unreachable for anyone else, and decide to remove it...

...but I imagine this would require some effort at link time, and I don't see this behavior mandated by the standard.

Also, I'm not sure if the compiler/linker is even allowed to remove the initialization of non-local variables, if that initialization has side effects.

melak47
  • 4,772
  • 2
  • 26
  • 37