以下代码编译并给出结果(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 { }
};
该代码会调用foo
中Base
的{{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),或......
这似乎表明第一个例子不合法。这构建不良吗?如果是这样,为什么我没有收到错误?
答案 0 :(得分:2)
编辑:经过一番思考:如果你实例化它们,模板首先会被定义。因此,如果编译器已到达您实例化模板类的行,则第一个代码可以找到,因为模板首先被定义。