首页 > 解决方案 > 查找规则如何应用于类模板中默认成员初始值设定项中使用的名称?

问题描述

#include <iostream>
template<class T>
struct A{
    int c = T::a;
};
struct B{
    A<B> cc;
    static const int a = 0;
};
int main(){

}

GCC 和 Clang 都接受上面的例子。关于查找规则如何应用于类模板特化中的名称,该名称可能是导致类模板特化的隐式实例化的类的成员,在 c++20 或更早版本中尚不清楚。幸运的是,在目前的草案中已经很清楚了。
[basic.lookup#class.member.lookup-3]

如果 P 在 C 的完整类上下文中,则声明集是在 C 的范围内从紧随 C 的类说明符之后的 N 的单个搜索的结果,否则从P搜索。如果结果声明集不为空,则子对象集包含 C 本身,计算完成。

似乎该规则可以用于解释我在上面所说的大多数情况,但是,考虑上面的示例,它有点特殊。

非静态成员的定义cc会导致 specialization 的隐式实例化,A<B>此时,它还不是 class 的完整上下文B。因此,后续在范围内查找名称B应该从这一点开始。如果T::a用作类 template 的非静态成员的类型说明符,则A100% 确定编译器会报告一个错误,即aB.

但是,除了以下规则
temp.res#general-1

如果名称是依赖的(如 [temp.dep] 中指定的),则为每个特化(替换后)查找它,因为查找取决于模板参数。

我在标准中找不到任何措辞来说明隐式实例化是否A会导致查找规则应用于默认成员初始化程序中的名称,或者不在该点。

乍一看上面的规则,应该是指在实例化封闭类模板特化时要查找名称,然后a在范围内找不到,B因为此时它不被认为是一个完整的类,只有P可以找到这些可以到达的声明。

显然,GCC 和 Clang 考虑的行为T是一个完整的类型,a可以在T. 换句话说,这些编译器似乎不会立即执行实例化时间的T::a查找A。如果我错过了某个特殊规则,请指出。

标签: c++language-lawyer

解决方案


推荐阅读