Template static variable

Viewed 60322

I can't understand, why if we define static variable of usual (non-template) class in header, we have linker error, but in case of templates all works fine and moreover we will have single instance of static variable among all translation units:

It's template header (template.h):

// template.h
template<typename T>
class Templ {
public:
  static int templStatic;
};

template<typename T> Templ<T>::templStatic = 0;

It's first unit using template (unit1.cpp)

// unit1.cpp
#include "template.h"

int method1() {
  return Templ<void>::templStatic++;
}

Second unit here (unit2.cpp):

// unit2.cpp
#include "template.h"
int method2() {
  return Templ<void>::templStatic++;
}

And, finally, main.cpp:

// main.cpp
#include <iostream>
int method1();
int method2();

int main(int argc, char** argv) {
  std::cout << method1() << std::endl;
  std::cout << method2() << std::endl;
}

After compilling, linking and executing this code, we will have following output:

0
1

So, why in case of templates all works fine (and as expected) ? How compiler or linker handle this (we can compile each .cpp file in separated calling of compiler, and then link them with caling to linker, so compiler and linker don't "see" all .cpp files at same time) ?

PS: My compiler: msvcpp 9 (but checked on mingw too)

3 Answers

It's because template code is not source code; it's instructions on how to write source code.

The non-template static variable is actual source code, and the compiler will attempt to do exactly what you say by including something in twice. Hence, you have to initialize the static variable in a .cpp file, and only reference it in the .h file describing the class. It's equivalent to a global variable declared through extern.

When the compiler sees

template<class T> Templ{...};

it does nothing except make a note that the template exists. As far as it is concerned, there is no source code associated with Templ. The first time you actually refer to

Templ<int> Instance

the compiler looks at all the template<> code associated with Templ and uses it to construct a .h and a .cpp file (which exists only for the duration of compilation). Those files might look like this:

Temple_int.h
class Templ_int{
  public:
  static int templStatic;
};

Templ_int.cpp
#include "Templ_int.h"
Templ_int::templStatic = 0;

And every

Templ<int>

becomes a Templ_int. Thus, the source code to initialize the static variable only exists once, in a .cpp file created by the compiler. (Obviously, the actual compiler-specific implementation of this process would be robust against creating a class with a similar name to the template, etc.)

Related