c++ - Clang 拒绝仅通过专门化定义类模板的嵌套类的代码是否正确?

标签 c++ templates language-lawyer template-specialization incomplete-type

给定以下类模板:

template<typename T>
struct Outer
{
    struct Inner;

    auto f(Inner) -> void;
};

我们为 Outer 的每个特化单独定义 Inner:

template<>
struct Outer<int>::Inner {};

template<>
struct Outer<double>::Inner {};

然后为 Outer 的所有特化定义一次成员函数 f:

auto Outer<T>::f(Inner) -> void
{

}

但是 Clang (9.0.0) 提示:

error: variable has incomplete type 'Outer::Inner'

auto Outer<T>::f(Inner) -> void

                      ^

我们还可以通过为 Outer 的所有其他特化提供 Inner 的定义来避免编译器错误:

template<typename T>
struct Outer<T>::Inner {};

或者通过为每个特化单独定义f:

template<>
auto Outer<int>::f(Inner) -> void
{

}

template<>
auto Outer<double>::f(Inner) -> void
{

}

GCC 和 MSVC 都接受初始代码,这就引出了一个问题;这是 Clang 错误还是这三个错误中唯一一致的实现?

Try on Compiler Explorer

最佳答案

我认为 Clang 拒绝你的代码是错误的。我们必须问自己,你的函数声明和定义与

auto f(typename T::Inner) -> void;

// ...

template<typename T>
auto Outer<T>::f(typename T::Inner) -> void
{ }

在此示例中,T::Inner 显然是一个依赖类型。因此,在实例化之前,Clang 可能不会认为它是不完整的。在你的例子中也是如此吗?我会这么说。因为我们的标准中有这样的内容:

[temp.dep.type]

5 A name is a member of the current instantiation if it is

  • An unqualified name that, when looked up, refers to at least one member of a class that is the current instantiation or a non-dependent base class thereof. [ Note: This can only occur when looking up a name in a scope enclosed by the definition of a class template.  — end note ]
  • ...

A name is a dependent member of the current instantiation if it is a member of the current instantiation that, when looked up, refers to at least one member of a class that is the current instantiation.

9 A type is dependent if it is

  • ...
  • a member of an unknown specialization,
  • a nested class or enumeration that is a dependent member of the current instantiation,
  • ...

因此,第 9 段中的第一个项目符号涵盖了 typename T::Inner 的情况。这是一种依赖类型。

同时,第二个项目符号涵盖了您的情况。 Outer::Inner 是在 Outer 的当前实例中找到的名称,而且它是在 Outer 本身内部找到的,而不是在基类中找到的类(class)。这使得它成为当前实例化的依赖成员。该名称指的是嵌套类。这意味着第二个项目符号中的所有条件都适用,从而使 Outer::Inner 也成为依赖类型!

由于我们在这两种情况下都有依赖类型,因此编译器应该将它们同等地视为依赖类型。我的结论是 GCC 和 MSVC 是正确的。

关于c++ - Clang 拒绝仅通过专门化定义类模板的嵌套类的代码是否正确?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58936617/

相关文章:

c++ - 如何实现is_pointer?

ruby-on-rails - 在助手中渲染 content_for block

c++ - 标准布局和尾部填充

c++ - 这两个说法在N4140中不是不兼容吗?

c++ - "Concurrency in Action"中的线程池示例

c++ - include 语句的顺序在链接步骤中有何影响?

c++ - 字距调整文本居中

c++ - 我对 enable_if 和 has_member 做错了什么?

c++ - 在头文件中定义成员对象时调用非空构造函数

c++ - 相同类型对象的列表初始化优先级