C ++ dynamic_cast转发声明的类模板编译,但是它安全吗?

时间:2015-07-10 05:44:48

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

以下代码编译并给出结果(GCC和clang):

template <typename T> struct Derived;

struct Base
{
    template <typename T>
    void foo(T * const t)
    {
        dynamic_cast<Derived<T> * const>(this)->bar(t);
    }
};

template <typename T>
struct Derived : Base
{
    void bar(T const *) const { }
};

该代码会调用fooBase的{​​{1}}来bar中的Derived

作为参考,以下代码无法编译:

struct Derived2;

struct Base2
{
    template <typename T>
    void foo(T * const t)
    {
        dynamic_cast<Derived2 * const>(this)->bar(t);
    }
};

struct Derived2 : Base2
{
    template <typename T>
    void bar(T const *) const { }
};

GCC提供以下诊断:

main.cpp: In member function 'void Base2::foo(T*)':
main.cpp:126:45: error: invalid use of incomplete type 'struct Derived2'
         dynamic_cast<Derived2 * const>(this)->bar(t);
                                             ^
main.cpp:119:8: note: forward declaration of 'struct Derived2'
 struct Derived2;
        ^

C ++ 14标准在One Definition Rule一节中说明如下:

  

5翻译单元中只需要一个类的定义   如果以一种需要类类型的方式使用该类   完成。
  [例如:以下完整的翻译单位是   格式良好,即使它从未定义X:
  struct X; //将X声明为结构类型
  struct X * x1; //在指针形成中使用X   X * x2; //在指针形成中使用X    - 例子]
  [注:规则为   声明和表达式描述了哪些上下文完成了类   类型是必需的。在以下情况下,类类型T必须完整:   (5.1) - 定义类型为T的对象(3.1)或
  (5.2) - 声明类型为T的非静态类数据成员(9.2)或
  (5.3) - T用作new-expression(5.3.4)或
中的对象类型或数组元素类型   (5.4) - 左值转换应用于参考类型为T(4.1)的对象的glvalue,或者
  (5.5) - 将表达式(隐式或显式)转换为类型T(第4,5.2.3,5.2.7,5.2.9,5.4)或者
  (5.6) - 一个不是空指针常量的表达式,并且具有cv void *以外的类型,使用标准转换(第4章),动态广播(5.2.7)转换为T的类型指针或引用T )或static_cast(5.2.9),或......

这似乎表明第一个例子不合法。这构建不良吗?如果是这样,为什么我没有收到错误?

1 个答案:

答案 0 :(得分:2)

编辑:经过一番思考:如果你实例化它们,模板首先会被定义。因此,如果编译器已到达您实例化模板类的行,则第一个代码可以找到,因为模板首先被定义。