Затеняет ли параметр конструктора вложенного класса члены включающего класса?

class A
{
  private:
    int a;

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

        int b;
    };
};


int main(void)
{
  return 0;
}

clang (-Weverything) предупреждает:

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;

Я знаю, что, поскольку вложенные классы C++11 имеют доступ к внешним классам, как если бы они были друзьями, но B просто объявлен внутри AB нет объекта-члена A, как может B параметр конструктора a тень A член a ?

Если вы прокомментируете aв B, все составители согласятся, что вы ссылаетесь на A::aДемо (что неверно, поскольку не static), поэтому они согласны с тем, что int a тени A::a.

Jarod42 24.07.2024 15:32

для поиска имени не имеет значения, что в A нет экземпляра B, A::a все равно находится. вложенные классы странные, я стараюсь их избегать

463035818_is_not_an_ai 24.07.2024 15:35

¯\_(ツ)_/¯ Кланг не ошибается. Вы можете перепутать параметр с членом класса, даже если он является членом включающего класса и недоступен.

HolyBlackCat 24.07.2024 15:35
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
11
3
238
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Затеняет ли параметр конструктора вложенного класса члены включающего класса?

Да.

Для поиска имени не требуется экземпляр A в B. Поскольку B вложено внутрь A, неквалифицированный поиск имени находит A::a.

Из cppreference:

Для имени, используемого в любом месте определения класса (включая спецификаторы базового класса и определения вложенных классов), за исключением тела функции-члена, аргумента по умолчанию функции-члена, спецификации исключения функции-члена или инициализатора члена по умолчанию, где член может принадлежат вложенному классу, определение которого находится в теле включающего класса, поиск осуществляется в следующих областях:

а) тело класса, в котором имя используется до момента использования,

б) все тело его базового класса(ов), рекурсивно обращающееся к их базам, когда объявления не найдены,

в) если этот класс вложен, тело включающего класса до определения этого класса и все тело базового класса(ов) включающего класса,

[...]

в) означает, что неквалифицированный незатененный a внутри B относится к A::a. Ваш код работает, потому что int a тени A::a и потому что в списке инициализаторов b(a) используется параметр конструктора с именем a.

То, что включающий класс является другом, на данном этапе не имеет значения, поскольку доступ осуществляется после поиска имени. Как отметил Jarod42, вы можете изменить код (переименовать параметр, но сохранить b(a)), чтобы получить ошибку, поскольку A::a не статичен.


Спасибо Artyer за пример, где член a действительно можно использовать для чего-то:

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) {}
    };
};

Мне было бы любопытно увидеть пример, где неквалифицированный поиск имени приводит к A::a, как в коде OP, и его действительно можно использовать без ошибок. мне не удалось найти ни одного

463035818_is_not_an_ai 24.07.2024 16:00

«означает, что неквалифицированное (незатененное) a внутри B относится к A::a...» Нет, в этом примере неквалифицированное a внутри B относится к параметру конструктора a. Под (незатененной) частью вы, вероятно, имели в виду, что если бы параметр ctor не был назван так же, как элемент данных, то он ссылался бы на этот элемент.

user12002570 24.07.2024 16:18

ок, namelookup/shadow не подразумевает возможного использования, поэтому предупреждение правильное (хотя иногда и раздражающее)

albert 24.07.2024 16:18

@albert Да, предупреждение верное.

user12002570 24.07.2024 16:18

@463035818_is_not_an_ai decltype может использовать нестатические элементы данных без уточнения имени класса. Например, class B { decltype(a) b; } находит A::a и decltype(a) -> decltype(A::a) -> int: godbolt.org/z/E6PfYGbP5

Artyer 24.07.2024 17:44

@user12002570 user12002570 Я переосмыслил себя, чтобы больше не обращать внимания на ваши комментарии. Вы можете удалить их. Или вы можете оставить их здесь. Хотя без контекста (моих комментариев) они проливают довольно искаженный свет на этот вопрос.

463035818_is_not_an_ai 26.07.2024 11:58

Другие вопросы по теме