在嵌套名称说明符中使用simple-template-id是否明确表示类模板特化?


struct A{
template<typename U>
void T(){}
};
struct B{
template<typename U>
struct T{
using type = U;
};
};
struct C:A,B{
};
int main(){
C::T<int>::type d;
}

GCC和Clang都不接受这个例子。

根据basic.lookup.qual#1

类或名称空间成员或枚举数的名称可以在::作用域解析操作符([expr.prim.id.qual])之后引用,该操作符应用于表示其类、名称空间或枚举的嵌套名称说明符。如果嵌套名称说明符中的::作用域解析操作符前面没有decltype说明符,则查找::前面的名称时只考虑特化类型为的名称空间、类型和模板。.

这意味着当查找模板名称T的声明时,T的专门化应在此上下文中表示类型。另一方面,根据class.member.lookup#4

如果C包含名称f的声明,则声明集包含C中声明的满足查找发生的语言结构要求的所有f声明.

同样,当在C范围内查找模板T时,只有那些专门化是类型的模板才应该被此查找考虑。C的作用域没有针对T的任何声明,因此将在S(T,C)的每个基类中对其执行查找。A中的T模板不满足要求。同时,在B的作用域中声明的模板T也满足要求。因此,查找不是二义性的,B::T是唯一的结果。这意味着C::T<int>::type d应该是格式良好的。为什么GCC和Clang都拒绝这个例子?它可以被认为是两者的bug吗?如果我遗漏了什么,那么这个例子是病态的原因是什么呢?

前瞻需要对T的查找依赖于::,即使<的解释依赖于T的含义被认为是不可取的。因此,查找后跟<的名称并不局限于类型和名称空间,而不管后面是否找到任何>::。P1787R6修复了这个问题,限制了对标识符的特殊查找,立即然后是::(因为其他类型的名称无论如何都不能引用类型或名称空间)。

最新更新