4

Consider the following code:

#include <iostream>

struct M {
    M() { std::cout << "M\n"; }
};

template <class T>
struct Test {
    Test() { std::cout << "Test\n"; }
    inline static auto m = M{};
};
int main() {
    Test<int> t1;
    //Test t;
    //(void)&t1.m;
}

Using the latest GCC or Clang the only "Test" is printed out. But if we use an address of m object (uncomment the last line (void)&t1.m;) or transform Test class template into the regular (non-templated) class then the M constructor was called.

Is this behaviour allowed by the C++ standard? Any quotes?

αλεχολυτ
  • 4,792
  • 1
  • 35
  • 71

1 Answers1

5

Yes, it's spelled out in the standard.

[temp.inst] (emphasis mine)

4 Unless a member of a class template or a member template is a declared specialization, the specialization of the member is implicitly instantiated when the specialization is referenced in a context that requires the member definition to exist or if the existence of the definition of the member affects the semantics of the program; in particular, the initialization (and any associated side effects) of a static data member does not occur unless the static data member is itself used in a way that requires the definition of the static data member to exist.

Since your example doesn't use the static data member at all, its definition is never fully instantiated.

StoryTeller - Unslander Monica
  • 165,132
  • 21
  • 377
  • 458
  • And from the previous clause regarding that definitions will not be instantiated as part of implicit instantiation, [\[temp.inst\]/3.1](https://timsong-cpp.github.io/cppwp/n4861/temp.inst#3.1), _"The implicit instantiation of a class template specialization causes the implicit instantiation of the declarations, **but not of the definitions**, of [...] static data members"_. This may be relevant as an explicit instantiation definition _will_ lead to the definition of the static data member(s) of that instantiation. – dfrib Oct 06 '20 at 07:56
  • @dfri - The OP did not use an explicit instantiation definition. That would be a subject for another question. – StoryTeller - Unslander Monica Oct 06 '20 at 08:02
  • Do you know any background why instantiation of static data member of templates is optional versus for regular class? Maybe a link to existing question on SO? – αλεχολυτ Oct 06 '20 at 08:05
  • @StoryTeller-UnslanderMonica Imho it's possibly interesting/relevant _context_, but this is purely opinion-based, hence my _"This may be relevant"_ (surely no need to include it in an answer to the post, but readers of the post _may_ not know of these subtle details). – dfrib Oct 06 '20 at 08:06
  • @αλεχολυτ - It's not just static data members. It's all members subject to the ODR. And this done in the interest of savings. Don't pay what you don't use (as a library user). – StoryTeller - Unslander Monica Oct 06 '20 at 08:06
  • @αλεχολυτ - BTW, if you want to force it, adding an ODR-use of the static variable in the constructor of `Test<>` should do it. – StoryTeller - Unslander Monica Oct 06 '20 at 08:09
  • I understand about conception "don't pay for unused things" but how does this correlate with regular class? The member is still unused for non-templated class, but ... always instantiated. – αλεχολυτ Oct 06 '20 at 08:16
  • 1
    @αλεχολυτ - No, not instantiated. It's **defined**. The inline is a red-herring here. We are talking about rules that predate that. For non-templates, you'd orignally declare the static member in the class and then add a definition in some TU. That definition incurs initialization. Templates don't instantiate definitions unless they really need them, as a matter of design. – StoryTeller - Unslander Monica Oct 06 '20 at 08:22