Take a look at the following code:
#include <iostream>
template <typename T>
class Foo
{
public:
static T bar;
};
template <typename T> typename T Foo<T>::bar;
int main() {
std::cout << "Foo<int>::bar : " << &Foo<int>::bar << std::endl;
std::cout << "Foo<double>::bar : " << &Foo<double>::bar << std::endl;
return 0;
}
This will print out 2 different addresses. I can understand why in this case, bar
is of type T
and thus instantiations of different T's in Foo<T>
will get you different static members. However, if we change bar
to a type we already know ( e.g. static int bar
) this still happens.
Why is this the case? Why just not re-use bar
for multiple template instantiations? How would I be able to get just 1 bar
object throughout different instantiations?
The static member is declared or defined inside the template< … > class { … } block. If it is declared but not defined, then there must be another declaration which provides the definition of the member.
The static declaration can be of template argument type or of any defined type. The statement template T K::x defines the static member of class K , while the statement in the main() function assigns a value to the data member for K <int> .
A class template is a template that is used to generate classes whereas a template class is a class that is produced by a template.
Inside a class, a normal member belongs to an object. A static member is shared between all objects of that type, and even exists before any object of that class is created.
There is nothing really surprising going on here.
template <typename T>
class Foo
{
//...
};
Is not a class, it is a template to stamp out classes. That means Foo<A>
is a completely different class from Foo<B>
. As such all static members are unique to the different instantiated classes — and the fact that class template being same has no relevance in this context, as it is after all a template, the blueprint of the instantiated classes.
If you want all the different kinds of Foo
's to share a common state then you can have them inherit from the same base class and put the common information there. Here is a very boiled down example:
struct Foo_Base
{
static int bar;
};
int Foo_Base::bar = 10;
template<typename T>
struct Foo : Foo_Base {};
int main()
{
Foo<int> foo_i;
Foo<double> foo_d;
std::cout << foo_i.bar << "\n";
foo_i.bar += 10;
std::cout << foo_d.bar;
}
output:
10
20
Live Example
From the standard, $14.7/6 Template instantiation and specialization [temp.spec]
Each class template specialization instantiated from a template has its own copy of any static members.
Foo<int>
and Foo<double>
are irrelevant classes, even though they're instantiated from the same template, and they will have their own static member bar
, even though their types are same (e.g. both int
).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With