Why type alias is allowed as name of variable?

616 Views Asked by At

What rule makes the following code compile without error:

using integer = int;

struct Foo
{
    int integer;
};

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

using is of course not a simple replacement for #define integer int, but what makes this code apparently well-formed while int int; would make it ill-formed?

2

There are 2 best solutions below

0
On BEST ANSWER

While it's a little surprising that one can access a name declared in an outer scope, and then later hide that name , it's just a straightforward application of the rules for scoping:

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]

In turn, the point of a name's declaration is:

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

So when you do integer integer, you haven't yet declared the block-scoped name integer, which means you can still see the global integer. This also means you cannot do integer integer = (integer)0.

It's easier to explain why int int won't compile. int is a keyword, so no syntactic rule which could declare it as a name would be able to; it doesn't match the rules for "what a name looks like".

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

Because int is a keyword, it cannot be an identifier, which means it cannot be a name.

2
On

The reason the code compiles is that the uses of integer are in different scopes.

using integer = int; // #1

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

Note that there is no relation between integer in #1 and #2. There is no clash between these uses, and they might as well have different names.

Inside Foo, the symbol integer refers only to the variable. If you want to refer to the type alias, you can prepend ::, like this:

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

If the using declaration and the variables are in the same scope, then you get an error:

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

or

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