Channel72
Channel72

Reputation: 24739

static member variable in class template

When you have a (non-templated) class that contains a static member, like:

class Foo
{
   public:

   static int x;
};

Then Foo::x must be defined in one and only one translation unit, or the compiler will complain of multiple definitions. So in somefile.cpp you'd have to define it:

int Foo::x = 10;

This way, any translation unit that accesses Foo::x is accessing the same memory address.

But what if Foo is a class template?

template <class T>
class Foo
{
   public:

   static int x;
};

Now, Foo<T>::x can be defined in a header file, by saying:

template <class T>
int Foo<T>::x = 10;

So, if class template Foo is defined in foo.hpp, and translation_unit1.cpp and translation_unit2.cpp both include foo.hpp, will the memory address of Foo<T>::x for some instantiation of template class Foo, (such as Foo<int>::x for example) be different for each translation unit?

Upvotes: 10

Views: 6063

Answers (3)

Lingxi
Lingxi

Reputation: 14987

Your question is perfectly answered by 14.4 in the C++11 standard:

A template name has linkage (3.5). A non-member function template can have internal linkage; any other template name shall have external linkage...

Therefore, a class template will always have external linkage and so are its static data members (const or not). So, Foo<int>::x will always refer to the same entity in memory regardless of which translation units this expression appears in. The linker makes this happen.

Upvotes: 2

Shafik Yaghmour
Shafik Yaghmour

Reputation: 158629

This is perfectly fine, in this case of defining it in the header the compiler will insure there is only one instance, if we see the draft C++ standard section 3.2 One definition rule paragraph 6 says(emphasis mine):

There can be more than one definition of a class type (Clause 9), enumeration type (7.2), inline function with external linkage (7.1.2), class template (Clause 14), non-static function template (14.5.6), static data member of a class template (14.5.1.3), member function

we can then go to section 14.5.1.3 Static data members of class templates paragraph 1 says:

A definition for a static data member may be provided in a namespace scope enclosing the definition of the static member’s class template.

and provides the following example:

template<class T> class X {
  static T s;
};
template<class T> T X<T>::s = 0;

Upvotes: 5

dyp
dyp

Reputation: 39151

[basic.def.odr]/6 explicitly allows multiple definitions of "static data members of a class template" (alongside other exceptions) under some circumstances.

It then continues for such an entity D:

If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Therefore the address of a static data member of a template instantiated in one TU compares equal to the address of the same static data member instantiated in another TU.


The complete quote, passages mentioned above emphasized by me:

There can be more than one definition of a class type, enumeration type, inline function with external linkage, class template, non-static function template, static data member of a class template, member function of a class template, or template specialization for which some template parameters are not specified in a program provided that each definition appears in a different translation unit, and provided the definitions satisfy the following requirements. Given such an entity named D defined in more than one translation unit, then

  • each definition of D shall consist of the same sequence of tokens; and
  • in each definition of D, corresponding names, looked up according to 3.4, shall refer to an entity defined within the definition of D, or shall refer to the same entity, after overload resolution and after matching of partial template specialization, except that a name can refer to a const object with internal or no linkage if the object has the same literal type in all definitions of D, and the object is initialized with a constant expression, and the value (but not the address) of the object is used, and the object has the same value in all definitions of D; and
  • in each definition of D, corresponding entities shall have the same language linkage; and
  • in each definition of D, the overloaded operators referred to, the implicit calls to conversion functions, constructors, operator new functions and operator delete functions, shall refer to the same function, or to a function defined within the definition of D; and
  • in each definition of D, a default argument used by an (implicit or explicit) function call is treated as if its token sequence were present in the definition of D; that is, the default argument is subject to the three requirements described above (and, if the default argument has sub-expressions with default arguments, this requirement applies recursively).
  • if D is a class with an implicitly-declared constructor, it is as if the constructor was implicitly defined in every translation unit where it is odr-used, and the implicit definition in every translation unit shall call the same constructor for a base class or a class member of D.

If D is a template and is defined in more than one translation unit, then the preceding requirements shall apply both to names from the template’s enclosing scope used in the template definition, and also to dependent names at the point of instantiation. If the definitions of D satisfy all these requirements, then the program shall behave as if there were a single definition of D. If the definitions of D do not satisfy these requirements, then the behavior is undefined.

Upvotes: 1

Related Questions