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

标签 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 { }
};

代码将对 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/

相关文章:

c++ - 单个指针是否可以指向两个或多个变量

c++ - 访问模板化基类的模板化方法

c++ - 为什么类型在自动和模板函数情况下都没有推导为 `const` 类型?

c++ - 当类包含在另一个类中时,为什么不转发类工作的声明

C++ - 占位符如何工作(特别是在 boost::type_erasure 中)?

c++ - 开场流量不好?

c++ - 声明/定义顺序依赖

c++ - 如何转发声明自定义unique_ptr

c++ - std::string 的解密有额外的填充字节?

templates - 如何使用 C++ 模板传递函数及其签名(haskell 样式)?