理解令人困惑的typedef语法

时间:2011-12-13 12:25:39

标签: c++ c typedef language-lawyer

考虑以下代码段

typedef int type;
int main()
{
   type *type; // why is it allowed?
   type *k ;// which type?
}

我收到错误'k' is not declared in this scope。编译器将type *k解析为type*k之间的乘法。这个语法不是很混乱吗?

为什么C ++标准允许type *type?因为语法是这样说的?为什么呢?

5 个答案:

答案 0 :(得分:23)

type *type; // why is it allowed?

C ++ 11 3.3.2 / 1说:

  

名称的声明点紧跟在完整的声明者(第8条)之后和初始化者之前(如果有的话)

因此,在使用类型名称type之后才会引入变量名type;类型名称是声明符期间type唯一可用的含义。

type *k ;// which type?

本地变量名称隐藏全局类型名称,因此在此处选择。这在C ++ 11 3.3.10 / 1中描述:

  

可以通过嵌套声明性区域或派生类中相同名称的显式声明来隐藏名称。

完全限定的类型名称::type当然仍然可用。

答案 1 :(得分:15)

问题实际上是关于何时将变量名称定义为标识符,并且语言确定它恰好在声明变量的代码中的点之后:

typedef int type;
int main() {
   type t;   // type refers to ::type
   int       // type still refers to ::type
   type;     // variable declared, this shadows ::type
   type + 1; // type is a variable of type int.
}

在其他情境中也有类似的规则,只需要决定何时声明标识符。还有其他类似的情况,例如在类的初始化列表中:

struct test {
   int x;          // declare member
   test( int x )   // declare parameter (shadows member)
   : x(            // refers to member (parameter is not legal here)
        x )        // refers to parameter
   {};
};

或者在成员函数定义中的标识符范围内:

struct test {
   typedef int type;
   type f( type );
};
test::type         // qualification required, the scope of the return type is
                   // at namespace level
test::f(
         type t )  // but the scope of arguments is the class, no qualification
                   // required.
{}

截至该决定的理由,我不能告诉你,但它是一致和简单的。

答案 2 :(得分:3)

令人困惑,但这是访问type变量的唯一方法。 如果您想使用type类型,您可以执行以下操作:

typedef int type;
int main() {
    type *type;
    ::type *k ;
    return 0;
} 

大多数语法怪物来自与C的向后兼容性。

答案 3 :(得分:1)

保持名称空间(不是在C ++中,但在变量/类型名称空间中)的基本原理是相当明显的:当您不使用类型名称污染变量名称空间时,在typedef上的代码中断次数会减少。

假设存在一个名为“employee”的变量的预先存在的代码。如果变量和typedef存在于同一名称空间中,则为“typedef struct {} employee;”会破坏现有代码,需要更改变量名称(这在IDE之前的日子里更是一个问题)。但是,如果他们共享一个命名空间,那么没有问题,人们在大型代码库中选择类型名称时会担心一个问题。

答案 4 :(得分:0)

我认为这可能是因为它为程序员在为他们声明的变量选择名称时提供了灵活性。在C#中,您可以声明与类型相同的属性:

//C# code
class Manager
{
   public Name Name {get;set;}
};

当我在C#中编码时,我觉得这个功能非常有用。因为我有更多的名字可供选择。否则,如果我有一个名为Name的类型,那么我将无法创建一个同名的属性,我将强制选择一个不同的名称,比如{ {1}},Name__Namename等 - 所有这些都不会吸引我。


至于你的代码,因为在范围内(在声明对象 NAME之后),type已经是变量,类型 `type不能直接引用。但我认为这应该编译好并且根据标准:

type

演示:http://ideone.com/chOov