模板参数类型被编译器视为完整的,但其定义尚不可见

Template parameter type is treated as complete by the compiler, but its definition isn't yet visible

假设我有以下代码片段:

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),我们会得到一个编译时错误 "incomplete type T",而且似乎很清楚:class Bar 实例化是由 (4) 启动的,在那点 class Foo 仅由 (3) 向前声明,尚未由 (5) 定义。

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

中进行

我错过了什么,为什么代码片段中的代码可以编译?

UPDATE:代码在 GCC 8.2.0 和 MSVC 19.16.27025.1 下编译,但在 Clang 7.0.0 下会出现 "incomplete type" 错误。

按照标准,在隐式实例化过程中,只实例化成员函数的声明,而不实例化它们的定义。

[temp.inst]/2 - The implicit instantiation of a class template specialization causes

  • the implicit instantiation of the declarations, but not of the definitions, of the non-deleted class member functions, member classes, scoped member enumerations, static data members, member templates, and friends ...

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

[temp.explicit]/11 - An explicit instantiation definition that names a class template specialization explicitly instantiates the class template specialization and is an explicit instantiation definition of only those members that have been defined at the point of instantiation.

clang 拒绝代码。