为什么默认情况下隐藏模板基 class' public 成员类型?

Why is a template base class' public member types hidden by default?

template<typename T>
struct A
{
    using U = T;
};

template<typename T>
struct B : A<T>
{
    B(typename A<T>::U) {} // okay
    B(U) {} // error: unknown type name 'U'
};

int main()
{
    return typename B<int>::U{}; // okay
}

为什么模板基础 class' public 成员类型默认隐藏?

进一步研究的搜索词是“两阶段名称查找”。

简而言之,编译器会尝试在定义模板的位置解析尽可能多的模板使用的名称。一些名称——所谓的“依赖名称”——此时无法解析,必须推迟到模板实际实例化并且其参数已知为止。粗略地说,这些是根据模板参数出现的语法名称。

U 本身不是从属名称,因此编译器会在编译 B 的定义时尝试解析它。它现在无法查看 A<T> 内部 - 它不知道 T 会是什么,或者是否会针对 T 进行 A 的特化可能会也可能不会声明名为 U 的成员。然后查找找不到 U 的声明,因此出现错误。

U in A<T>::U 是一个从属名称,它的查找被推迟到 B<int> 被实例化。此时,编译器还实例化 A<int> 并可以在其中查找 U.

的声明

这也是为什么需要在typename A<T>::U中写typename的原因。编译器无法查找依赖名称 U 的声明,但它至少需要知道它是一个类型还是非类型,因为低级词法分析依赖于它(经典例如 X*Y; 可以被解析为指针的声明,或使用乘法的表达式,具体取决于 X 是否为类型)。所以规则是,依赖名称被假定为引用非类型,除非前面有 typename 关键字。