Question

Does a constructor parameter of a nested class shadow members of the enclosing class?

class A
{
  private:
    int a;

  public:
    class B
    {
      public:
        B(int a) : b(a) {}

        int b;
    };
};


int main(void)
{
  return 0;
}

clang (-Weverything) warns:

t.cpp(10,15): warning: constructor parameter 'a' shadows the field 'a' of 'A' [-Wshadow-field-in-constructor]
   10 |         B(int a) : b(a)
      |               ^
t.cpp(4,9): note: previous declaration is here
    4 |     int a;

I know that since C++11 nested classes have access to outer classes as if they were friends, but B is just declared inside A (there is no member object of B in A, how can B constructor param a shadow A member a ?

 10  187  10
1 Jan 1970

Solution

 6

Does a constructor parameter of a nested class shadow members of the enclosing class?

Yes.

Name lookup needs no A instance in B. Because B is nested inside A, unqualified name lookup finds A::a.

From cppreference:

For a name used anywhere in class definition (including base class specifiers and nested class definitions), except inside a member function body, a default argument of a member function, exception specification of a member function, or default member initializer, where the member may belong to a nested class whose definition is in the body of the enclosing class, the following scopes are searched:

a) the body of the class in which the name is used until the point of use,

b) the entire body of its base class(es), recursing into their bases when no declarations are found,

c) if this class is nested, the body of the enclosing class until the definition of this class and the entire body of the base class(es) of the enclosing class,

[...]

c) means that an unqualified unshadowed a inside B refers to A::a. Your code works because int a shadows A::a and because in the initializer list b(a) uses the constructor parameter called a.

That the enclosing class is a friend does not matter at this point, because access comes after name lookup. As Jarod42 pointed out, you can modify the code (rename the parameter but keep b(a)) to get an error because A::a is non static.


Thanks to Artyer for an example where the member a can actually be used for something:

struct A {
    int a;
    struct B {
      public:
        decltype(a) b;      // equivalent to decltype(A::a) b;

        B(int a) : b(a) {}  // int a shadows A::a
                            // equivalent to B(int x) : b(x) {}
    };
};
2024-07-24
463035818_is_not_an_ai