多个嵌套的依赖名称 - 在哪里粘贴typename关键字? [英] multiple nested dependent names - where to stick the typename keyword?
问题描述
此问题的灵感来自这个其他问题。在试图回答这个问题时,我明白我自己有很多问题。所以...考虑以下内容:
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,但你不真的知道在哪里粘。 范围操作符之前的名称 标准说( 隐含地假定在mem-initializer-id,base-specifier或elaborated-type-specifier中用作名称的限定名称来命名一个类型,而不使用 这部分显然可以有,在豁免列表中包含typedef声明的 type-specifier 。但请记住,类型说明符可能变得非常复杂,特别是在typedef声明。现在,在typedef 类型说明符中多次需要 在 如果限定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: This compiles successfully with MSVC9.0 and Online Comeau. However, what's bothering me is that I don't understand what I have tried these 2 syntaxes (syntaces?) of what I think it should be both of which fail on MSVC: and Of course, a workaround is to use consecutive 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.
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; //带或不带此行,编译失败。
}
::
必须始终是命名空间或类(或枚举)名称,并且命名空间名称不能是依赖的。所以你不必告诉编译器这是一个类名。
[temp.res]
):
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
。
typename
关键字,因此需要进行更多的分析来说服我 typename 在typedef中不是必需的。
typedef typename T :: Type :: Type Type
, T :: Type :: Type
需要使用 typename
关键字,因为其 nested-name-specifier ( T :: Type ::
)是一个依赖名称, :
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;
}
typename
refers to in (1) and why wouldn't we need typename
in (2). 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 this: typedef typename T::Type T1;
typedef typename T1::Type Type;
enum { value = Type::value};
Please note, that although MSVC accepts the original strange syntax without multiple typename
s(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 thetypename
keyword. [ Note: Thetypename
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屋!