为什么默认情况下隐藏模板基 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
关键字。
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
关键字。