3
#include <iostream>

template <typename T>
class Temp {
 public:
  static Temp temp;
  Temp() { std::cout << "hi!"; }
};

// Definition.
template <typename T>
Temp<T> Temp<T>::temp;

I created a simple template class. I thought that instantiating Temp object is enough to construct static temp in Temp.

int main() {
  Temp<int> t;
}

But this only returned one "hi!".

Whereas if I explicitly reference the temp,

int main() {
  Temp<int> t;
  Temp<int>::temp;
}

it printed "hi!" two times and I could confirm that the static object was created during its usual initialization time (before calling main). Whats the criteria on compiler to omit the construction of static object? Also how do I enforce it other than referencing it?

Jaebum
  • 1,397
  • 1
  • 13
  • 33
  • @dxiv is there any reference I can find about it? – Jaebum Dec 23 '20 at 05:24
  • 2
    Don't have the standard handy, but see the reference at the end of the question [C++ Static member initialization (template fun inside)](https://stackoverflow.com/questions/1819131/c-static-member-initialization-template-fun-inside). Correction to my first (now deleted) comment: template static members are not created if not referenced, or the specialization explicitly declared. – dxiv Dec 23 '20 at 05:28
  • 1
    It's fairly fundamental to how templates work that unused code isn't instantiated, e.g. things like `std::vector` with a non copyable type works as long as you don't call certain methods – Alan Birtles Dec 23 '20 at 07:12

1 Answers1

0

You can explicitly instantiate the class to make it more likely that the static member is included without referencing it:

template class Temp<int>;

Note, however, that depending on compiler/linker options, unreferenced code isn't necessarily included into the final binary. In particular, any attempt to register something using an object is bound to fail! For example, for large builds it is quite common to use dedicated sections for functions and objects and ELF linkers will only include referenced sections.

Template are in general only instantiated when needed. Normally that implies they are referenced ("ODR-used" in the standard). You can force instantiation with an explicit instantiation as demonstrated above. However, even after instantiation by the compiler, the linker can throw out unused code. Sure, something registering an object into some registry isn't "unused code" from your perspective but it is unused code from the linkers perspective. The linker normally works in terms of sections which in turn are normally based on files but there are options to specify sections or force the compiler to generate more fine-grained sections to reduce the size of the executable.

Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380