一个可编辑的例子:
的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抱怨
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,
^
即使MyClass在模板实例化时应该是可见的。为什么呢?
修改 在例子中修正了一个拼写错误。
答案 0 :(得分:6)
实例化声明的效果,即保证模板未被隐式实例化,根据14.7.2 [temp.explicit]第10段不适用于inline
函数:
除了内联函数,从其初始值或返回值(7.1.6.4)推导出的类型的声明,文字类型的常量变量,引用类型的变量和类模板特化,显式实例化声明具有抑制隐式的效果实例化他们所涉及的实体。 [注意:意图是当使用odr(3.2)时,仍然会隐式实例化作为显式实例化声明主题的内联函数,以便可以考虑使用内联体,但是不需要外联副本内联函数的内容将在翻译单元中生成。-end note]
标准库显然可以将其任何功能声明为inline
。也就是说,使用实例化声明不会影响使用标准库模板类定义的类型的要求(当然,除非另有说明)。 gcc在此类模板的定义中定义std::unique_ptr<...>
的析构函数,使其隐式内联。以下是演示该问题的示例源:取决于是否DECL_ONY
定义了编译器:
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;
}