class A
{
};
template <typename A, int S>
class B
{
public:
static int a[S];
B()
{
a[0] = 0;
}
};
template<> int B<A, 1>::a[1];
int main()
{
B<A, 1> t;
t;
}
It compiles under GCC 4.1, but does not link:
static.cpp:(.text._ZN1BI1ALi1EEC1Ev[B<A, 1>::B()]+0x5): undefined reference to `B<A, 1>::a'
I would prefer to keep initialisation specialised if it is possible, since the array holds some data specific to the type.
For static member specializations, if you don't initialize the member, it is taken as a specialization declaration, that just says "Oh, don't instantiate the member from the primary template, because there is a specialized definition somewhere else". It should be mentioned that the definition should appear in a .cpp file (otherwise, you will earn the opposite: multiple definitions), and the declaration without initializer should still be placed in the header file.
Now the correct syntax is indeed the following, and it should not appear in a header file, but in a .cpp
file
template<> int B<A, 1>::a[1] = { };
The following should still appear in a header file:
template<> int B<A, 1>::a[1];
This will serve as the specialization declaration.
From this, it follows that you can't specialize a member that only has a default constructor and is not copyable, because you would need this syntax:
// needs a copy constructor!
template<> Type Class<Arguments>::member = Type();
C++0x fixes this:
// doesn't anymore need a copy constructor
template<> Type Class<Arguments>::member{};
For the Standardese people among us, here are the quotes:
14.7.3/6
:
If a template, a member template or the member of a class template is explicitly specialized then that specialization shall be declared before the first use of that specialization that would cause an implicit instantiation to take place, in every translation unit in which such a use occurs; no diagnostic is required.
14.7.3/15
:
An explicit specialization of a static data member of a template is a definition if the declaration includes an initializer; otherwise, it is a declaration. [Note: there is no syntax for the definition of a static data member of a template that requires default initialization.
template<> X Q<int>::x;
This is a declaration regardless of whether X can be default initialized (8.5). ]
3.2/3
:
Every program shall contain exactly one definition of every non-inline function or object that is used in that program; no diagnostic required.
3.2/5
:
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.5), static data member of a class template (14.5.1.3), member function of a class template (14.5.1.1), or template specialization for which some template parameters are not specified (14.7, 14.5.4) in a program [...]
The restriction of this to "for which some template parameters are not specified" means that we are allowed to do the following, placing it into a header (thus possibly having multiple definitions of this specialization):
template<> template<typename T>
Type OuterClass<int>::InnerClass<T>::StaticMember = 0;
In your case, you have all parameters specified, making it not being covered by the one defintion rule for allowing multiple definitions.
You need to actually assign a value to it.
template<> int B<A, 1>::a[1] = {0};
It does not link because you don't define a value to your static member.
template<> int B<A, 1>::a[] = { 0 };
Edit:
Btw: I would always prefer to use boost::array instead of native C-types:
class A { };
template <typename A, std::size_t S>
class B
{
public:
static boost::array<int, S> a;
B() { a[0] = 0; }
};
template<> boost::array<int, 1> B<A, 1>::a = { };
int main()
{
B<A, 1> t;
cout << t.a[0] << endl;
}
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