Search code examples
c++gccvisual-c++typedef

Variable with same name as type gives no compilation error when placed in function, struct or class


Given the Code:

#include <iostream>

typedef int Integer;
Integer Integer = 1234;

int main() {
    std::cout <<  "Integer: " << Integer;
}

Compiling the code with the gcc 11.2 Compiler will result in compilation errors:

error: 'Integer Integer' redeclared as different kind of entity
    4 | Integer Integer = 1234;
      |         ^~~~~~~

note: previous declaration 'typedef int Integer'
    3 | typedef int Integer;
      |             ^~~~~~~

In function 'int main()':
error: expected primary-expression before ';' token
    7 |         std::cout <<  "Integer: " << Integer;
      |                                             ^

However, changing the code to:

#include <iostream>

typedef int Integer;

int main() {
    Integer Integer = 1234;
    std::cout <<  "Integer: " << Integer;
}

will not result in a compilation error.
I tried using the gcc 11.2, clang 12.0.1 and MSVC 19.29 Compiler and all failed at the first version but allowed the second one.
Why does the second version work while the first one fails?


Solution

  • The difference is one of scope.

    In the first example, both Integers are declared in the global scope:

    typedef int Integer;
    Integer Integer = 1234;
    

    In the second example, one is declared in the global scope, whereas the other is local to main:

    typedef int Integer;
    int main() {
        Integer Integer = 1234;
        ...
    }
    

    It works because, at the moment the compiler reads the first Integer inside main, there is only one entity with that name, so it must refer to the type in the global scope. But once you've declared a variable with the name Integer inside main, you cannot use that name again to refer to the type instead:

    typedef int Integer;
    int main() {
        Integer Integer = 1234; // OK because only the type is visible.
        Integer otherInteger = 567; // Error because Integer is a variable here.
        ::Integer thirdInteger = 89; // OK because :: resolves to the global one.
    }