Arm*_*yan 10 c++ templates dependent-name typename
这个问题的灵感来自另一个问题.在尝试回答这个问题时,我明白自己有很多问题.所以......考虑以下几点:
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;
}
Run Code Online (Sandbox Code Playgroud)
这与MSVC9.0和Online Comeau成功编译.但是,困扰我的是我不理解typename(1)中提到的内容以及为什么我们不需要typename(2).
我已经尝试过这两种语法(合成器?),我认为它应该是MSVC上的两种失败:
typedef typename T::typename Type::Type Type;
enum {value = typename T::typename Type::Type::value };
Run Code Online (Sandbox Code Playgroud)
和
typedef typename (typename T::Type)::Type Type;
enum {value = (typename (typename T::Type)::Type)::value };
Run Code Online (Sandbox Code Playgroud)
当然,解决方法是使用这样的连续typedefs:
typedef typename T::Type T1;
typedef typename T1::Type Type;
enum { value = Type::value};
Run Code Online (Sandbox Code Playgroud)
抛开好的风格,我们在语法上必须使用我提到的解决方法吗?
其余的只是一个有趣的例子.无需阅读.与问题无关.
请注意,虽然MSVC接受没有多个typenames 的原始奇怪语法(我的意思是(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.
}
Run Code Online (Sandbox Code Playgroud)
这不编译.我提到的解决方法解决了这个问题,但我确信这里的问题是我最初的问题 - 缺少typename,但你真的不知道在哪里贴一个.首先十分感谢.
范围运算符之前的名称::必须始终是命名空间或类(或枚举)名称,并且命名空间名称不能相关.因此,您不必告诉编译器这是一个类名.
我不仅仅是这样做,标准说(部分[temp.res]):
在mem-initializer-id,base-specifier或elaborated-type-specifier中用作名称的限定名称被隐式假定为命名类型,而不使用
typename关键字.在一个嵌套名称说明符直接包含一个嵌套名称说明符依赖于模板参数,标识符或简单模板id被隐含地假设命名类型,而不使用的typename关键字.[注意:typename这些结构的语法不允许使用关键字. - 结束说明]
T::,, T::Type::和T::Type::Type::是嵌套名称说明符,它们不需要标记typename.
这一部分显然可以,并且可以说应该包含豁免列表中typedef声明的类型说明符.但请记住,类型说明符可能会变得非常复杂,尤其是在typedef声明中.现在很可能typename在typedef 类型说明符中多次需要关键字,因此需要更多的分析来说服我typename在typedef中永远不需要.
在typedef typename T::Type::Type Type,T::Type::Type需要使用typename关键字,因为它的嵌套名称说明符(T::Type::)是一个从属名称,标准说(相同部分):
当qualified-id旨在引用不是当前实例化成员的类型(14.6.2.1)并且其嵌套名称说明符引用依赖类型时,它应该由关键字typename预先定义,形成一个TYPENAME说明符.如果typename-specifier中的qualified-id不表示类型,则程序格式错误.