将typename关键字与typedef和new一起使用

时间:2010-12-12 10:53:41

标签: c++ templates typedef language-lawyer typename

考虑这段代码,

template<class T>
struct Sample
{ 
     typename T::X *x; //declare pointer to T's X
};

在上面的代码中,编译器需要关键字typename,以便它可以消除模板中嵌套类型和嵌套值之间的歧义。这意味着,在没有typename关键字的情况下,编译器会将此解释为T :: X与x的乘法,

T::X *x; //multiply T::X with x

因此,在可能出现歧义的情况下,关键字typename变为必需,以消除歧义。但是,上下文本身消除歧义的情况很少。 other topic讨论了基类和函数参数的上下文(后者虽然没有消除歧义)。在本主题中,我特别想讨论其他两个似乎明确的上下文,但我们仍然需要编写typename

typedef typename T::X xtype;
pX = new typename T::X;  

在这两种情况下,关键字typedefnew使编制者清楚地知道后面的内容是 type 不是 < EM>值。

所以我的问题是,为什么编译器仍需要typename关键字,即使在明确的情况下,例如我们使用typedefnew时?


编辑(从Johannes Schaub读取此回复后):

//typedef NOT followed by a type!
int typedef A;

这种语法要求我稍微修改一下我的问题,以便我可以看到其他人看到的问题。

考虑一下,

T::X typedef *x;

所以从上下文来看,编译器仍然清楚T :: X是一个类型,无论它出现在 typedef之前,还是之后 em> typedef除非C ++允许我们编写typedef 5 fivetypedef T::value t_value(其中T :: value是 value ),typedef本身的存在会消除所有歧义,所以,typename似乎是标准的必要条件(在这种情况下)。同样的论点也适用于new


另外,我编写了一个使用此结构作为模板参数的类模板:

struct A 
{
        struct X { string name; };
        static const int X = 100;
};

我特别想知道以下代码(来自构造函数)是否正确(可移植),

//two interesting statements
 pX = new typename T::X; //T::X means struct X
 product = T::X * p; //but here, T::X means int X

完整代码在ideone处为here。请在回复之前先看一下。 : - )

3 个答案:

答案 0 :(得分:14)

C ++语法比这更疯狂。

// typedef NOT followed by a type!
int typedef A;

// new NOT followed by a type!
new (0) int;

其他人评论了你的例子。 typename说明符不会导致查找忽略非类型名称。因此,如果您说new typename T::X,并且X中有一个对象名称T,则仍会找到它而不是类型名称X(但GCC会忽略非类型在typename之后查找名称的名称。但这不符合标准)。


编辑答案:

  

考虑一下,

T::X typedef *x;
     

所以从上下文来看,编译器仍然清楚T :: X是一个类型,无论它是出现在typedef之前还是出现在typedef之后。

编译器必须知道声明说明符的时间和(即“类型部分”以及声明者部分何时开始(即“名称”部分)。有声明类型部分为空的声明:

// constructor definitions don't need a type section
MyClass::MyClass() { }

// conversion function definitions don't need a type section
MyClass::operator int() { }

如果您指定的名字不是类型,则类型部分结束,名称部分开始。说T::X告诉编译器:

  

现在我要定义T::X

它从左到右读取,因此当它遇到typedef时会认为你忘记了分号。内部课程的解释略有不同,但也很像这样。这是一个简单而有效的解析。

  

同样的论点也适用于新的。

我倾向于同意你的意见。从语法上来说,它应该是明确的如果你不用括号。由于我从未编写过C ++解析器,因此可能存在隐藏的陷阱,但我没有看到。

typename语言的每一个new的添加都可能需要为编译器和标准编写者设计大量的设计,而绝大多数仍然需要typename其他需要的情况。我认为这不会带来回报。

答案 1 :(得分:0)

  

那为什么编译器仍然需要typename关键字?

因为语言的规则是以这种方式表达的:在类型上下文中使用的每个从属名称必须在typename之前( mutatis mutandis ,同样适用于模板名称和template关键字)。现在,为什么语言规则不会在需要typename来消除歧义的情况和上下文提供足够信息的情况之间产生差异?可能 - 在作出决定时我不在场 - 保持语言描述更加复杂(考虑失踪案件的后果,不管是哪种方式)。

在您的示例中,X不是类型名称(如果与C兼容,则标签名称不是自动类型名称的可能性),因此您需要使用struct

pX = new struct T::X;

答案 2 :(得分:0)

您的代码似乎进入了一个非常灰暗的区域。

关于名字隐藏的这一段

  

类名(9.1)或枚举名称   (7.2)可以隐藏一个名字   变量,数据成员,函数或   枚举器在同一范围内声明。   如果是类或枚举名称和   变量,数据成员,函数或   枚举器声明在同一个   范围(以任何顺序)与相同   name,类或枚举名称是   隐藏在变量,数据的任何地方   成员,函数或枚举器名称   是可见的。

似乎表明编译器抱怨A::X不是类型名称是正确的。