No definition available for static const member wi

2019-07-05 23:46发布

问题:

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?

  1. 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.)
  2. In this case, the value has a constant initializer so the compiler can in theory simply use the value directly.
  3. 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.

回答1:

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.



回答2:

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.