模板的外部模板参数化为不完整类型

时间:2014-12-22 19:54:19

标签: c++ templates c++11 forward-declaration incomplete-type

一个可编辑的例子:

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

修改 在例子中修正了一个拼写错误。

1 个答案:

答案 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;
}