20

考虑这段代码,

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成为必要,以消除歧义。但是,上下文本身消除歧义的情况很少。另一个主题讨论了基类和函数参数的上下文(尽管后者并没有消除歧义)。在这个话题中,我特别想讨论其他两个似乎没有歧义的上下文,但我们仍然需要写typename

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

在这两种情况下,关键字typedefnew让编译器清楚地知道后面的内容是type而不是 value

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


编辑(在阅读了Johannes Schaub的回复后):

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

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

考虑到这一点,

T::X typedef *x;

因此,从上下文来看,编译器仍然很清楚 T::X 是一种类型,无论它出现在 之前 typedef还是之后 typedef除非 C++ 允许我们写typedef 5 five or typedef 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。回复前请看一下。:-)

4

3 回答 3

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,并且 中有一个对象名称XT它仍然会被找到而不是类型名称X(但是,GCC 在查找 a 之后的名称时会忽略非类型名称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. 在类内部,解释略有不同,但也很相似。这是一个简单而有效的解析。

同样的论点也适用于 new 。

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

typename像 in 这样的语言在极端情况下的每一次添加new都可能需要编译器和标准编写者进行大量设计,同时仍然需要typename绝大多数其他需要它的情况。我不认为这是有回报的。

于 2010-12-12T12:47:16.813 回答
0

那为什么编译器还需要 typename 关键字呢?

因为语言的规则是这样制定的:在类型上下文中使用的每个从属名称必须在前面加上typename比照了,模板名称和template关键字也是如此)。现在,为什么语言规则在需要类型名来消除歧义的情况和上下文提供足够信息的情况之间没有区别?可能 - 做出决定时我不在场 - 使语言描述更加复杂(考虑丢失案例的后果,一种或另一种方式)。

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

pX = new struct T::X;
于 2010-12-12T11:26:15.480 回答
0

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

这一段关于名字隐藏

类名 (9.1) 或枚举名 (7.2) 可以被同一范围内声明的变量、数据成员、函数或枚举数的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器以相同的名称在同一范围内(以任何顺序)声明,则无论变量、数据成员、函数或枚举器名称可见。

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

于 2010-12-12T11:26:16.873 回答