查找规则如何应用于类模板中默认成员初始值设定项中使用的名称?
#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用作 class template 的非静态成员的类型说明符,则A100% 肯定编译器会报告错误,指出a在 的范围内找不到任何标识符B。
但是,除了下面的规则
temp.res#general-1
如果名称是相关的(如 [temp.dep] 中所指定),则为每个特化(替换后)查找它,因为查找取决于模板参数。
我在标准中找不到任何说明隐式实例化是否A会导致查找规则应用于默认成员初始值设定项中的名称或不在该点的任何措辞。
乍一看上面的规则,它应该意味着在实例化封闭类模板特化时应该对名称进行查找,然后a在范围内找不到,B因为此时它不被视为完整的类,只有P可以找到这些可到达的声明。
显然,GCC 和 Clang 考虑的行为T是一个完整的类型,a可以在T. 换句话说,这些编译器似乎不会立即执行实例化T::a时的查找A。如果我遗漏了某个特殊规则,请指出。