Given:
template<class T>
struct S {
static int const N = 1;
};
extern template class S<int>;
template<class T>
int f( T n ) {
return n + S<T>::N; // line 10
}
int main() {
return f(1); // line 14
}
//template class S<int>; // intentionally commented out to trigger error
I get:
foo.cpp: In function ‘int f(T) [with T = int]’:
foo.cpp:10: instantiated from ‘const int S<int>::N’
foo.cpp:10: instantiated from ‘int f(T) [with T = int]’
foo.cpp:14: instantiated from here
foo.cpp:10: error: explicit instantiation of ‘S<int>::N’ but no definition available
But why do I get the error?
- The point of doing an explicit template instantiation declaration is so that the definitions can be elsewhere, yet the compiler (not the linker) gives an error. (In a real application, the currently commented out explicit instantiation declaration would be in another translation unit anyway.)
- In this case, the value has a constant initializer so the compiler can in theory simply use the value directly.
- When I don't do the explicit template instantiation declaration, I (oddly) don't have to explicitly define
S<T>::N
.
This is with g++ 4.2.1 on Mac OS X 10.6.6.
From 9.4.2/2:
The declaration of a static data
member in its class definition is not
a definition and may be of an
incomplete type other than cvqualified
void. The definition for a static data
member shall appear in a namespace
scope enclosing the member’s class
definition. In the definition at
namespace scope, the name of the
static data member shall be qualified
by its class name using the ::
operator.
And from 9.4.2/4:
If a static data member is of const
integral or const enumeration type,
its declaration in the class
definition can specify a
constantinitializer which shall be an
integral constant expression (5.19).
In that case, the member can appear in
integral constant expressions within
its scope. The member shall still be
defined in a namespace scope if it is
used in the program and the namespace
scope definition shall not contain an
initializer.
From these references we can infer ("...shall still be defined..." in 9.4.2/4) that if it's not defined then the program isn't well-formed.
extern template class S<int>;
I think this line causes the error, as it tells the compiler to look for explicit instantiation of S<int>
somewhere, but no explicit instantiation exists. Hence the error.
Once you comment this line, I think the code should compile fine.
EDIT:
Well, see this : http://www.ideone.com/oQnOi
As I said, it compiles fine!
EDIT:
I think $9.4.2/4 (as quoted by Mark B) doesn't apply to the static members of class templates, as $14.5.1.3 [temp.static] doesn't mandate the static members to be defined at namespace scope:
A definition for a static data member
may be provided in a namespace scope
enclosing the definition of the static
member’s class template.
The the example follows as,
template<class T> class X { static T s; };
template<class T> T X<T>::s = 0;
Notice, it doesn't say "must be provided", rather "may be provided". So I think the definition of static members of class template at namespace scope is optional.