Reputation: 1883
A compilable example:
main.cpp
#include "test.h"
int main(int argc, char* argv[]) {
auto myPtr = std::unique_ptr<MyClass>(getMyPtr());
}
test.h
#ifndef TEST_H
#define TEST_H
#include <memory>
class MyClass;
extern template class std::unique_ptr<MyClass>;
MyClass* getMyPtr();
#endif
test.cpp
#include "test.h"
class MyClass {};
template class std::unique_ptr<MyClass>;
MyClass* getMyPtr() { return new MyClass; }
g++ 4.9.2 complains
In file included from c:/devel/mingw32/i686-w64-mingw32/include/c++/memory:81:0,
from main.cpp:4:
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h: In instantiation of 'void std::default_delete<_Tp>::operator()(_Tp*) const [with _Tp = MyClass]':
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h:236:16: required from 'std::unique_ptr<_Tp, _Dp>::~unique_ptr() [with _Tp = MyClass; _Dp = std::default_delete<MyClass>]'
main.cpp:64:53: required from here
c:/devel/mingw32/i686-w64-mingw32/include/c++/bits/unique_ptr.h:74:22: error: invalid application of 'sizeof' to incomplete type 'MyClass'
static_assert(sizeof(_Tp)>0,
^
even though MyClass should be visible at the point of template instantiation. Why?
Edit: fixed a typo in example.
Upvotes: 9
Views: 799
Reputation: 154045
The effects of instantiation declarations, i.e., a guarantee that the template is not instantiated implicitly, does not apply to inline
functions according to 14.7.2 [temp.explicit] paragraph 10:
Except for inline functions, declarations with types deduced from their initializer or return value (7.1.6.4), const variables of literal types, variables of reference types, and class template specializations, explicit instantiation declarations have the effect of suppressing the implicit instantiation of the entity to which they refer. [ Note: The intent is that an inline function that is the subject of an explicit instantiation declaration will still be implicitly instantiated when odr-used (3.2) so that the body can be considered for inlining, but that no out-of-line copy of the inline function would be generated in the translation unit.—end note ]
The standard library is clearly free to declare any of its functions as inline
. That is, using an instantiation declaration doesn't affect the requirement on types being defined with standard library template class (unless otherwise specified, of course). gcc defines the destructor for std::unique_ptr<...>
in the definition of this class template making it implicitly inline. Here is an example source demonstrating the problem: depending on whether DECL_ONY
is defined it compiler or not:
template <typename T>
struct foo
{
~foo()
#ifdef DECL_ONLY
;
#else
{ static_assert(sizeof(T), "defined!"); }
#endif
};
#ifdef DECL_ONLY
template <typename T>
foo<T>::~foo() { static_assert(sizeof(T), "defined!"); }
#endif
class MyClass;
extern template struct foo<MyClass>;
int main(int , char* []) {
foo<MyClass> f;
}
Upvotes: 6