Reputation: 1257
I wanted to check that the extern
keyword did infact prevent class code being generated in the translation unit:
template<class> struct always_false : std::false_type {};
template <typename T> class A{
static_assert(always_false<T>::value, "If this fires, 'A' is instantiated");
};
extern template class A<int>; //error: static assertion failed: If this fires, 'A' is instantiated|
int main(){
// A<int> f;
}
Why is it that the previous code still produces an error from the static_assert
if this is my only source file? As far as I understand from the explicit use of extern
this should prevent any production of code for the class A<int>
and the linker takes care of finding a later explicit instantiation definition (in the translation unit for which the code is actually written) to match any use of A<int>
with.
However it seems that the explicit instantiation declaration is generating code in this translation unit itself as indicated by the compilation error. If I comment out extern template class A<int>
everything works fine. I was using GCC 4.9.2. but it appears clang 3.5.1 throws this error too.
Alternatively this also kicks up the same assert error:
template<class> struct always_false : std::false_type {};
template <typename T> class A{
public:
void test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }
};
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Here I would've expected the member function A<int>::test()
to not even be instantiated and again wait until linking before "finding" code for the function, but it looks like the code is generated in the same translation unit. However if I take out the static_assert
:
template <typename T> class A{
public:
void test() { }
};
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Then I get the error I'm expecting, indicating that A<int>::test()
is not instantiated and there was a linker error:
**undefined reference to `A<int>::test()'|**
Why would the static_assert
throw an error if test()
was never instantiated?
Upvotes: 0
Views: 987
Reputation: 72225
Your premise is wrong. extern template
prevents object code generation for function templates (including member functions of class templates), but it doesn't prevent the instantiation of the class bodies.
Edit: To answer the updated question: the member function is defined inline in the class, so the compiler will still instantiate it so that it can inline it if necessary. If you define the function out of line, you will not get an error (tried GCC 5.2.0 via godbolt).
#include <type_traits>
template<class> struct always_false : std::false_type {};
template <typename T> class A{
public:
void test();
};
template <typename T>
void A<T>::test() { static_assert(always_false<T>::value, "If this fires, 'test()' is instantiated"); }
extern template void A<int>::test();
int main(){
A<int> a;
a.test();
}
Upvotes: 3