多个嵌套的依赖名称 - 在哪里粘贴typename关键字? [英] multiple nested dependent names - where to stick the typename keyword?

查看:215
本文介绍了多个嵌套的依赖名称 - 在哪里粘贴typename关键字?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

此问题的灵感来自这个其他问题。在试图回答这个问题时,我明白我自己有很多问题。所以...考虑以下内容:

  struct S1 
{
enum {value = 42}
};

template< class T> struct S2
{
typedef S1类型;
};

template< class T> struct S3
{
typedef S2< T>类型;
};

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)中为什么我们不需要<$ c $



我尝试过这两个语法我认为它应该是两个失败的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 s like like:

  typedef typename T ::类型T1; 
typedef typename T1 :: Type Type;
enum {value = Type :: value};

良好的风格留在一边,我们在语法上 / strong>使用我提到的解决方法?



其余的只是一个有趣的例子。无需阅读。

请注意,虽然MSVC接受原来的奇怪语法,但没有多个 typename s(我的意思是(1)和(2)),它导致奇怪的行为,如上面提到的问题。我想我将在这里以简洁的形式介绍这个例子:

  struct Good 
{
枚举{value = 1};
};
struct Bad
{
enum {value = -1};
};

template< class T1,class T2>
struct ArraySize
{
typedef坏类型;
};
template< class T>
struct ArraySize< T,T>
{
typedef好类型;
};

template< class T>
struct Boom
{
char arr [ArraySize< T,Good> :: Type :: value]; //错误,负下标,即使没有任何实例化
};

int main()
{
Boom< Good> b; //带或不带此行,编译失败。
}

这不会编译。我提到的解决方法解决了问题,但我确定这里的问题是我的初始问题 - 缺少typename,但你不真的知道在哪里粘。

解决方案

范围操作符之前的名称 :: 必须始终是命名空间或类(或枚举)名称,并且命名空间名称不能是依赖的。所以你不必告诉编译器这是一个类名。






标准说( [temp.res] ):


隐含地假定在mem-initializer-id,base-specifier或elaborated-type-specifier中用作名称的限定名称来命名一个类型,而不使用 typename 关键字。在直接包含取决于模板参数的 nested-name-specifier nested-name-specifier 中,标识符或simple-template-id隐含地假定为name一个类型,而不使用 typename 关键字。 [注意:
这些结构的语法不允许使用 typename 关键字。 - end note]


T :: T :: Type :: T :: Type :: Type :: nested-name-specifiers ,他们不需要标记 typename



这部分显然可以有,在豁免列表中包含typedef声明的 type-specifier 。但请记住,类型说明符可能变得非常复杂,特别是在typedef声明。现在,在typedef 类型说明符中多次需要 typename 关键字,因此需要进行更多的分析来说服我 typename 在typedef中不是必需的。



typedef typename T :: Type :: Type Type T :: Type :: Type 需要使用 typename 关键字,因为其 nested-name-specifier T :: Type :: )是一个依赖名称, :


如果限定ID用于指代不是当前实例化(14.6.2.1)成员的类型,其嵌套名称指定符指代依赖类型,它将由关键字typename预先定义,形成一个typename-specifier。如果typename-specifier中的qualified-id不表示类型,那么程序就会生成错误。



This question was inspired by this other question. While trying to answer that question, I understood that I have a lot of questions myself. So... Consider the following:

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;
}

This compiles successfully with MSVC9.0 and Online Comeau. However, what's bothering me is that I don't understand what typename refers to in (1) and why wouldn't we need typename in (2).

I have tried these 2 syntaxes (syntaces?) of what I think it should be both of which fail on MSVC:

    typedef typename T::typename Type::Type Type;
    enum {value = typename T::typename Type::Type::value }; 

and

    typedef typename (typename T::Type)::Type Type;
    enum {value = (typename (typename T::Type)::Type)::value }; 

Of course, a workaround is to use consecutive typedefs like this:

   typedef typename T::Type T1;
   typedef typename T1::Type Type;
   enum { value = Type::value};  

Good style left aside, do we syntactically have to use the workaround I mentioned?

The rest is just an interesting example. No need to read. Not that relevant to the question.

Please note, that although MSVC accepts the original strange syntax without multiple typenames(I mean (1) and (2)), it leads to strange behavior as in the mentioned question. I think I'll present that example in concise form here as well:

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.
}

This doesn't compile. The workaround I mentioned solves the problem, but I am sure the problem here is my initial question - missing typename, but you don't really know where to stick one. Thanks very much in advance.

解决方案

The name before the scope operator :: must always be a namespace or class (or enumeration) name, and namespace names can't be dependent. So you don't have to tell the compiler that this is a class name.


I'm not just making this up, the standard says (section [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 the typename keyword. [ Note: The typename keyword is not permitted by the syntax of these constructs. — end note ]

T::, T::Type::, and T::Type::Type:: are nested-name-specifiers, they do not need to be marked with typename.

This section clearly could have, and arguably should have, included the type-specifier of a typedef declaration in the list of exemptions. But remember that type-specifiers can get really complicated, especially in typedef declarations. Right now it's quite possible to need the typename keyword multiple times in a typedef type-specifier, so a lot more analysis would be needed to convince me that typename is never necessary in a typedef.

In typedef typename T::Type::Type Type, T::Type::Type requires use of the typename keyword, because its nested-name-specifier (T::Type::) is a dependent name, and the standard says (same section):

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.

这篇关于多个嵌套的依赖名称 - 在哪里粘贴typename关键字?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆