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.
When the name of a non-type template parameter is used in an expression within the body of the class template, it is an unmodifiable prvalue unless its type was an lvalue reference type, or unless its type is a class type (since C++20) .
In C++11, extern template feature is introduced to avoid this situation. Above will tell the compiler to not instantiate template function or class as it is being instantiated somewhere else. Programmer should use this if and only if above template function or class is instantiated somewhere else.
An identifier that names a non-type template parameter of class type T denotes a static storage duration object of type const T, called a template parameter object, whose value is that of the corresponding template argument after it has been converted to the type of the template parameter.
Template parameters can be types, non-types, and templates. Okay, types are the most often used template parameters. Here are a few examples: Integrals are the most used non-types. std::array is the typical example because you have to specify at compile time the size of a std::array: Templates can be template parameters.
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;
}
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