template<typename T>
struct A {
using U = typename T::U;
using V = typename T::V; //X
};
struct B {
using U = int;
void f() { A<B> a; } //1
//A<B> a; //2
using V = int;
};
这在当前的 GCC、Clang、MSVC 和 ICC(https://godbolt.org/z/dvExbxszn)上编译。
我想知道这是否实际上指定在标准中工作。A<B>
具体来说,允许B::U
和B::V
被查找的实例化点在哪里?
如果我们使用//2
而不是//1
,所有四个编译器都会拒绝代码,但如果//X
被删除则接受。对于这种情况,我理解严格阅读标准可能会使程序格式错误,即使//X
被删除,因为实例化点应该高于B
. 然而,按照CWG 287中的建议更改,编译器允许查找A::U
在需要实例化的点之前声明的A<B>
.
但是,需要从完整的类上下文中进行实例化,在void f() { A<B> a; }
我看来,编译器假定实例化点在 的定义之后B
,因此其中的所有名称B
都可用于在实例化中查找。这实际上是在标准中指定的,还是类似于 CWG 287 的情况,编译器试图使实例化的行为类似于非模板定义,反对对标准的严格解释?