【问题标题】:Template parameter type is treated as complete by the compiler, but its definition isn't yet visible模板参数类型被编译器视为完整,但其定义尚不可见
【发布时间】:2019-01-01 17:50:32
【问题描述】:

假设我有以下代码 sn-p:

template <class T>
class Bar
{
    // static_assert(sizeof(T) > 0); // (1)
public:
    void method()
    {
        static_assert(sizeof(T) > 0); // (2)
    }
};

class Foo; // (3)

template class Bar<Foo>; // (4)

class Foo{}; // (5)

如果我们取消注释第 (1) 行,我们会得到一个编译时错误“不完整类型 T”,并且似乎很清楚:class Bar 实例化由 (4) 启动,此时 class Foo仅由 (3) 前向声明,尚未由 (5) 定义。

但是如果第(1)行被注释掉,那么这段代码编译没有错误,这让我很困惑:(4)是一个显式模板实例化定义,它强制编译器生成void method()代码,并且行(2) 也应该产生同样的错误,因为Foo 的定义是在 (5) 后面进行的。

我错过了什么,为什么 sn-p 中的代码可以编译?

更新:代码在 GCC 8.2.0 和 MSVC 19.16.27025.1 下编译,但在 Clang 7.0.0 下会出现“不完整类型”错误。

【问题讨论】:

  • 用什么工具链编译(因为它用 vc++ (19.00.24215.1) 按原样呕吐?包括在你的问题中。
  • @WhozCraig 谢谢,我添加了描述。事实证明,clang 不会编译这个。

标签: c++ templates incomplete-type template-instantiation


【解决方案1】:

按照标准,在隐式实例化期间,仅实例化成员函数的声明,而不实例化它们的定义。

[temp.inst]/2 - 类模板特化的隐式实例化导致

  • 非删除类成员函数、成员类、范围成员枚举、静态数据成员、成员模板和朋友的声明的隐式实例化,但不是定义的隐式实例化......

但对于显式实例化,它并没有说同样的话。整个类被实例化,这意味着它实例化了method() 的定义,此时Foo 并不完整。

[temp.explicit]/11 - 显式实例化定义命名类模板特化显式实例化类模板特化,并且是仅在实例化点已定义的那些成员的显式实例化定义。

clang 拒绝代码。

【讨论】:

  • 确实,clang 不会编译它(我更新了问题描述)。那么,这是正确的行为吗?
猜你喜欢
  • 2011-12-14
  • 2013-07-02
  • 1970-01-01
  • 1970-01-01
  • 2021-07-25
  • 2019-08-27
  • 2022-01-24
  • 1970-01-01
相关资源
最近更新 更多