请考虑以下内容:
template<class> struct T
{
struct T1
{
struct T2
{
};
};
/*typename*/ T1::T2 m;
};
如果没有typename
,则编译将失败,因为T2被视为从属名称,因此不是类型。在考虑了C ++ 17草案标准(N4659)之后,我相信我已经确定了原因:
§17.6.2.1¶5
名称是当前实例的成员(如果它是
) —一种无限定名称,当查找时,该名称指的是类的至少一个成员,该类是当前实例或其非依赖基类。
...
名称是当前实例的依赖成员,如果它是当前实例的成员,则在查找时,该成员指的是类中至少一个成员是当前实例。
T1是当前实例的从属成员。 T2不是当前实例的成员(它是T1的成员),
§17.6.2.1¶9.3
如果类型是从属的,则是依赖的 ...
—作为当前实例的从属成员的嵌套类或枚举,
...
T1是一个嵌套类,因此是一个依赖类型。
§17.6¶3
当 qualified-id 旨在引用不属于当前实例(17.6.2.1)及其 nested-name-specifier 成员的类型时指从属类型,它必须以关键字 typename 为前缀,形成一个 typename-specifier 。 ...
因此,typename
是必需的。
我的理解正确吗?如果是这样,这背后的原理是什么? T1::T2
的查找如何找到嵌套在T1中的T2以外的任何东西?
答案 0 :(得分:4)
是的,您是正确的。
对于您而言,这并不重要,因为如果不实例化T1
(因为它是类成员),就不可能专门化m
。但是您可以这样做,将m
放在函数中:
template<class> struct T
{
struct T1
{
struct T2
{
};
};
void foo() {
typename T1::T2 m;
}
};
template<>
struct T<void>::T1 {
int T2;
};
如果T1
不依赖,则您的代码可能会更改含义,因为T2
将引用值而不是类型。