在 typedef 和 new 中使用 typename 关键字

考虑这个代码,

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

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

In the above code, the keyword typename is required by the compiler, so that it can disambiguate between nested types and nested values in templates. That means, in the absence of typename keyword, compiler would interpret this as multiplication of T::X with x,

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

因此在可能出现歧义的情况下,关键字typename 变成了necessity 以消除歧义.但是,上下文本身消除歧义的情况很少.其他主题讨论了基类和函数的上下文-参数(尽管后者不会消除歧义).在这个话题中,我特别想讨论另外两个看起来无歧义的上下文,但我们仍然需要写typename

So in such situations where ambiguity can arise, the keyword typename becomes necessity so as to remove ambiguities. But there are few situations when the context itself removes ambiguities. The other topic discusses contexts of base-class and function-parameters (the latter doesn't remove ambiguity though). In this topic, I particularly want to discuss other two contexts which seem to be unambiguous, but we're still required to write typename,

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

在这两种情况下,关键字typedefnew 足以让编译器清楚地知道接下来是type, 不是 价值.

In these two situations, the keywords typedef and new make it clear enough to the compiler that whatever follows is type, not value.

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

So my question is, why do compilers still need the typename keyword, even in unambiguous situations such as when we use typedef and new?

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

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

This syntax asks me to modify my question a little bit, so that the point which I'm trying to make, may be seen by others.

考虑一下,

T::X typedef *x;

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

So from the context, it's still clear enough to the compiler that T::X is a type, no matter whether it appears before typedef,or after typedef. Unless C++ allows us to write typedef 5 five or typedef T::value t_value (where T::value is value), the presence of typedef itself removes all ambiguities and so, typename seems to be an unnecessary requirement by the Standard (in such situations). Same argument holds true for new as well.

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

Also, I've written a class template which is using this struct as template argument:

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

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

I particularly want to know if the following code (from the constructor) is correct (portable) or not,

//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 此处.回复之前请先看一下.:-)

The complete code is here at ideone. Please have a look at it before replying. :-)

推荐答案

C++ 语法比这更疯狂.

C++ syntax is more crazy than that.

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

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

其他人对您的示例发表了评论.typename 说明符不会忽略非类型名称进行查找.所以如果你说new typename T::X,并且T中有一个对象名X,它仍然会被找到而不是类型名称 X (然而,GCC 在查找 typename 之后的名称时会忽略非类型名称.但这不符合标准).

Others have commented about your example. The typename specifier does not yield to lookup ignoring non-type names. So if you say new typename T::X, and there is an object name X in T, it will still be found instead of the type name X (GCC however ignores non-type names in looking up a name after a typename. But that's not Standards compliant).

对编辑的回答:

考虑一下,

T::X typedef *x;

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

So from the context, it's still clear enough to the compiler that T::X is a type, no matter whether it appears before typedef,or after typedef.

编译器必须知道声明说明符和(即类型部分"和声明符部分何时开始(即名称"部分).有些声明类型部分为空:

The compiler has to know when the declaration specifiers and (i.e the "type section" and when the declarator section start (i.e the "names" section). There are declarations where the type section is empty:

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

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

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

If the first name you specify is not a type, the type section ends, and the name section starts. Saying T::X tells the compiler:

现在我想定义T::X.

它从左到右读取,所以当它遇到typedef时它会认为你忘记了分号.在类内部,解释略有不同,但也很相似.这是一个简单而有效的解析.

It reads from left to right, so it will think you forgot a semicolon when it then encounters the typedef. Inside classes the interpretation is slightly different but much like this too. That's a simple and effective parse.

同样的论点也适用于 new.

Same argument holds true for new as well.

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

I tend to agree with you here. Syntactically it should be unambiguous if you leave off parentheses. As I've never written a C++ parser, there may be hidden pitfalls I'm not seeing, though.

在诸如 new 这样的语言的极端情况下,每次添加 typename 都可能需要为编译器和标准编写者进行大量的设计,同时仍然需要 typename 用于绝大多数其他需要它的情况.我不认为这是值得的.

Every addition of typename in corner cases of the language like in new will potentially require substantial amount of design for both compilers and standards writers, while still requiring typename for the vast majority of other cases where it's needed. I don't think that this pays off.

相关文章