外部模板,用于使用非竞争类型参数化的模板

Extern template for template parametrized with incompete type

本文关键字:竞争 类型参数 用于 外部      更新时间:2023-10-16

一个可编译的例子:

主.cpp

#include "test.h"
int main(int argc, char* argv[]) {
    auto myPtr = std::unique_ptr<MyClass>(getMyPtr());
}

测试.h

#ifndef TEST_H
#define TEST_H
#include <memory>
class MyClass;
extern template class std::unique_ptr<MyClass>;
MyClass* getMyPtr();
#endif

测试.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 在模板实例化时应该是可见的。为什么?

编辑:修复了示例中的拼写错误。

根据 14.7.2 [temp.explicit] 第 10 段,实例化声明的效果(即保证模板未隐式实例(不适用于inline函数:

除了内联函数、类型从其初始值设定项或返回值 (7.1.6.4( 推导的声明、文本类型的 const 变量、引用类型的变量和类模板专用化之外,显式实例化声明具有抑制它们所引用的实体的隐式实例化的效果。[注意:目的是作为显式实例化声明主题的内联函数在 odr 使用 (3.2( 时仍将隐式实例化,以便可以考虑内联主体,但不会在翻译单元中生成内联函数的外联副本。

标准库显然可以自由地将其任何功能声明为 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;
}