这个问题的灵感来自 this other question .在尝试回答这个问题时,我明白我自己也有很多问题。所以...请考虑以下事项:
struct S1
{
enum { value = 42 };
};
template <class T> struct S2
{
typedef S1 Type;
};
template <class T> struct S3
{
typedef S2<T> Type;
};
template <class T> struct S4
{
typedef typename T::Type::Type Type; //(1)//legal?
enum {value = T::Type::Type::value }; //(2)//legal?
};
int main()
{
S4<S3<S2<S2<S1> > > >::value;
}
这可以通过 MSVC9.0 和 Online Comeau 成功编译。但是,困扰我的是我不明白 typename
在 (1) 中指的是什么以及为什么我们不需要 typename
在 ( 2).
我已经尝试了这两种我认为应该在 MSVC 上失败的语法(语法?):
typedef typename T::typename Type::Type Type;
enum {value = typename T::typename Type::Type::value };
和
typedef typename (typename T::Type)::Type Type;
enum {value = (typename (typename T::Type)::Type)::value };
当然,解决方法是像这样使用连续的 typedef
:
typedef typename T::Type T1;
typedef typename T1::Type Type;
enum { value = Type::value};
抛开良好的风格,我们是否在句法上必须使用我提到的解决方法?
剩下的只是一个有趣的例子。无需阅读。与问题无关。
请注意,虽然 MSVC 接受没有多个 typename
的原始奇怪语法(我的意思是 (1) 和 (2)),但它会导致上述问题中的奇怪行为。我想我也会在这里以简洁的形式展示这个例子:
struct Good
{
enum {value = 1};
};
struct Bad
{
enum {value = -1};
};
template <class T1, class T2>
struct ArraySize
{
typedef Bad Type;
};
template <class T>
struct ArraySize<T, T>
{
typedef Good Type;
};
template <class T>
struct Boom
{
char arr[ArraySize<T, Good>::Type::value]; //error, negative subscript, even without any instantiation
};
int main()
{
Boom<Good> b; //with or without this line, compilation fails.
}
这不会编译。我提到的解决方法解决了这个问题,但我确信这里的问题是我最初的问题——缺少类型名,但你真的不知道该把它贴在哪里。 非常感谢。
最佳答案
范围运算符::
之前的名称必须始终是命名空间或类(或枚举)名称,并且命名空间名称不能依赖。所以你不必告诉编译器这是一个类名。
标准说([temp.res]
部分)不是我编造的:
A qualified name used as the name in a mem-initializer-id, a base-specifier, or an elaborated-type-specifier is implicitly assumed to name a type, without the use of the
typename
keyword. In a nested-name-specifier that immediately contains a nested-name-specifier that depends on a template parameter, the identifier or simple-template-id is implicitly assumed to name a type, without the use of thetypename
keyword. [ Note: Thetypename
keyword is not permitted by the syntax of these constructs. — end note ]
T::
、T::Type::
和 T::Type::Type::
是嵌套的-name-specifiers,它们不需要用typename
标记。
本节显然可以并且可以说应该在豁免列表中包含 typedef 声明的类型说明符。但请记住,类型说明符 可能会变得非常复杂,尤其是在 typedef 声明中。现在很可能在 typedef type-specifier 中多次需要 typename
关键字,因此需要更多的分析才能让我相信 typename
在 typedef 中永远不是必需的。
在 typedef typename T::Type::Type 类型
中,T::Type::Type
需要使用 typename
关键字,因为它的 nested-name-specifier (T::Type::
) 是一个从属名称,并且标准说(同一部分):
When a qualified-id is intended to refer to a type that is not a member of the current instantiation (14.6.2.1) and its nested-name-specifier refers to a dependent type, it shall be prefixed by the keyword typename, forming a typename-specifier. If the qualified-id in a typename-specifier does not denote a type, the program is ill-formed.
关于c++ - 多个嵌套的相关名称 - 在哪里粘贴 typename 关键字?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6642721/