Igor G
Igor G

Reputation: 2471

Why do compilers allow a data member have the same name as the class?

Three major compilers (gcc, clang, MSVC) happily compile the following example (godbolt):

struct Test
{
    // Member type `Test::Test` is supposedly introduced at this point
    // as an alias to `struct Test`, per
    // https://timsong-cpp.github.io/cppwp/n4659/class#2

    // Shouldn't the following declaration be rejected since it redefines
    // the name `Test` in the same scope?
    // https://timsong-cpp.github.io/cppwp/n4659/basic.lookup#3
    int     Test;

    // Doing the same explicitly would be a compilation error, as expected:
    // using   Probe = int;
    // int     Probe;
};

int main()
{
    Test    x;
    x.Test = 4;
}

Is the above example well-formed? and why. Why doesn't injected-class-name render the declaration of member int Test; invalid?

Lookup rule [wrong reference to a newer standard] that might have made the example ill-formed with no diagnostic seem irrelevant, as no lookup happens here until the class is complete. What other clauses are relevant to this example?

Upvotes: 4

Views: 260

Answers (1)

Vlad from Moscow
Vlad from Moscow

Reputation: 311126

According to the C++17 Standard (12.2 Class members)

18 If T is the name of a class, then each of the following shall have a name different from T:

(18.1) — every static data member of class T;

(18.2) — every member function of class T [ Note: This restriction does not apply to constructors, which do not have names (15.1) — end note ] ;

(18.3) — every member of class T that is itself a type;

(18.4) — every member template of class T;

(18.5) — every enumerator of every member of class T that is an unscoped enumerated type; and

(18.6) — every member of every anonymous union that is a member of class T.

and

19 In addition, if class T has a user-declared constructor (15.1), every non-static data member of class T shall have a name different from T.

So as your class does not have a user-declared constructor then its non-static data member Test may have the same name as the class name.

You may even write

Test Test;
Test.Test = 4;

(It seems it is allowed for compatibility with C where structure tag names and names of data members belong to different name spaces.)

On the other hand, if you will declare a constructor as for example

struct Test
{
    Test() = default;
    int     Test;
};

then the compiler will issue an error.

In general C++ does not allow for example to declare a variable and a function with the same name in the same scope.

Upvotes: 6

Related Questions