为什么允许类型别名作为变量名?

Why type alias is allowed as name of variable?

什么规则使得下面的代码compile without error:

using integer = int;

struct Foo
{
    int integer;
};

int main() {
    Foo f;
    int integer;
    f.integer;
}

using 当然不是 #define integer int 的简单替代,但是是什么让这段代码看起来格式正确,而 int int; 会使其格式错误?

代码编译的原因是integer的使用在不同的范围

using integer = int; // #1

struct Foo
{
    int integer;  // #2
};

请注意#1中的integer#2之间没有关系。这些用途之间没有冲突,它们也可能有不同的名称。

Foo中,符号integer仅指变量。如果你想引用类型别名,你可以在前面加上 ::,像这样:

struct Foo
{
  ::integer integer;  // ok
};

如果 using 声明和变量在 相同的 作用域中,则会出现错误:

using integer = int; 
int integer;          // error, redefinition of symbol 
                      // as different kind of entity

struct Foo
{
    using integer = int; 
    int integer;         // error, redefinition of symbol 
                         // as different kind of entity
};

虽然可以访问在外部作用域中声明的名称然后隐藏该名称有点令人惊讶,但这只是作用域规则的直接应用:

A name declared in a block (9.3) is local to that block; it has block scope. Its potential scope begins at its point of declaration (6.3.2) and ends at the end of its block. [basic.scope.block]

反过来,名称声明的要点是:

immediately after its complete declarator (Clause 11) and before its initializer (if any)... [basic.scope.pdecl]

所以当你做integer integer时,你还没有声明block-scoped名称integer,这意味着你仍然可以看到全局integer。这也意味着你不能integer integer = (integer)0.

更容易解释为什么 int int 无法编译。 int 是一个关键字,因此没有语法规则可以将其声明为名称;它不符合“名字的样子”的规则。

There are five kinds of tokens: identifiers, keywords, literals, operators, and other separators. [lex.token]

因为int是关键字,不能是标识符,也就是说不能是名字。