以下代码在(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 { }
};
代码将对 Base
中的 foo
的调用分派(dispatch)到 Derived
中的 bar
。
作为引用,以下代码无法编译:
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 标准在单一定义规则部分规定如下:
5 Exactly one definition of a class is required in a translation unit if the class is used in a way that requires the class type to be complete.
[ Example: the following complete translation unit is well-formed, even though it never defines X:
struct X; // declare X as a struct type
struct X* x1; // use X in pointer formation
X* x2; // use X in pointer formation
—end example ]
[ Note: The rules for declarations and expressions describe in which contexts complete class types are required. A class type T must be complete if: (5.1) — an object of type T is defined (3.1), or
(5.2) — a non-static class data member of type T is declared (9.2), or
(5.3) — T is used as the object type or array element type in a new-expression (5.3.4), or
(5.4) — an lvalue-to-rvalue conversion is applied to a glvalue referring to an object of type T (4.1), or
(5.5) — an expression is converted (either implicitly or explicitly) to type T (Clause 4, 5.2.3, 5.2.7, 5.2.9, 5.4), or
(5.6) — an expression that is not a null pointer constant, and has type other than cv void*, is converted to the type pointer to T or reference to T using a standard conversion (Clause 4), a dynamic_cast (5.2.7) or a static_cast (5.2.9), or ...
这似乎表明第一个例子是不合法的。这是构造错误的?如果是这样,为什么我没有收到错误消息?
最佳答案
编辑:经过一番思考:如果实例化模板,首先会定义模板。因此,如果编译器到达您实例化模板类的行,您的第一个代码会找到,因为模板首先被定义。
关于C++ dynamic_cast 转发声明的类模板编译,但它安全吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31333301/