Clang 是不是正确拒绝仅通过特化定义类模板的嵌套类的代码?
Posted
技术标签:
【中文标题】Clang 是不是正确拒绝仅通过特化定义类模板的嵌套类的代码?【英文标题】:Is Clang correct to reject code in which the nested class of a class template is defined only via specializations?Clang 是否正确拒绝仅通过特化定义类模板的嵌套类的代码? 【发布时间】:2020-03-15 02:59:15 【问题描述】:给定以下类模板:
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
【问题讨论】:
Inner 的特殊性无关紧要,删除它们不会改变编译结果。 @n.'pronouns'm。我不确定你是什么意思。 adding a definition ofInner
for all other specializations 和 defining f
separately for each specialization 都解决了编译错误。
我们再读一遍:删除它们并不会改变编译结果。不添加,不删除。 gccclang
@n.'pronouns'm。我现在明白你的意思了,但这仍然是一个奇怪的评论。我的问题的重点是 Inner
被报告为不完整的类型,尽管提供了 Outer
的每个专业化的定义。如果您删除它的定义,Inner
显然会(正确地)是一个不完整的类型。
"如果您删除它的定义,显然 Inner 将(正确地)是一个不完整的类型。" 不,这根本不是 ckear。特化是一个完全独立的模板,它不会完全影响主模板。
【参考方案1】:
我认为 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一个名字是一个当前实例化的成员如果它是
一个非限定名称,在查找时,它指的是当前实例化或非依赖类的至少一个成员 其基类。 [ 注意:这只能在查找名称时发生 在类模板定义所包含的范围内。 - 结尾 注意 ] ...一个名字是一个当前实例化的依赖成员如果它是 当前实例化的成员,在查找时指代 当前实例化的类的至少一个成员。
9一个类型是依赖的,如果是的话
... 未知专业的成员, 一个嵌套类或枚举,它是当前实例化的依赖成员, ...
所以第 9 段中的第一个项目符号涵盖了typename T::Inner
的情况。那是一个依赖类型。
同时,您的案例已被第二个项目符号覆盖。 Outer::Inner
是在Outer
的当前实例化中找到的名称,而且它在Outer
本身中找到,而不是在基类中。这使它成为当前实例化的依赖成员。此名称指的是嵌套类。这意味着第二个项目符号中的所有条件都适用,从而使 Outer::Inner
也成为依赖类型!
由于在这两种情况下我们都有自己的依赖类型,编译器应该将它们平等地视为依赖类型。我的结论是 GCC 和 MSVC 是对的。
【讨论】:
Bug reported。谢谢。以上是关于Clang 是不是正确拒绝仅通过特化定义类模板的嵌套类的代码?的主要内容,如果未能解决你的问题,请参考以下文章