Имеет ли друг в классе вложенного класса доступ к внешним членам класса? - PullRequest
14 голосов
/ 04 апреля 2019

clang ++, g ++ и MSVC не согласны с этим кодом :

class A {
private:
    enum class E { NO, YES };
    class B {
    private:
        friend E f1() { return E::YES; }
        // friend E f2();
    };
};

// A::E f2() { return A::E::YES; }

int main() {}

clang ++ принимает код, как показано. G + + и MSVC жалуются в f1, что A::E недоступен. Если функция f2 не закомментирована, все три компилятора жалуются, что A::E недоступен.

Действительно ли f1 действителен?

Соответствующие Стандартные образцы, которые я нашел:

[class.access.nest]

Вложенный класс является членом, и поэтому имеет те же права доступа, что и любой другой член.

Хотя это само по себе не означает, что друзья вложенного класса имеют все те же права, что и вложенный класс.

[class.access.base] / 5

Доступ к члену зависит от класса, в котором он назван. Этот класс именования является классом, в котором имя члена было найдено и найдено. Элемент m доступен в точке R при названии в классе N, если

  • m как член N является публичным, или

  • m как член N является личным, а R встречается у члена или друга класса N или

  • m как член N защищен, и ..., или

  • существует базовый класс B из N, который доступен в R , а m доступен в R при названии в классе B.

То есть f2 недопустимо, поскольку класс имен для A::E определенно равен A, базовые классы не задействованы, а определение f2 не является членом или другом A и не "встречается" у участника или друга A.

В f1 класс именования для неквалифицированного E также равен A. ([basic.lookup.unqual] говорит, что сначала выполняется поиск имени E в классе A::B, но там его не «находят», поэтому выполняется поиск в классе A, и член найден.) Но я думаю, что главный вопрос в том, встречается ли определение f1 в члене A? Этот член, если так, должен быть class A::B.

1 Ответ

6 голосов
/ 04 апреля 2019

Я думаю, что gcc и msvc правы.

От [class.friend] / 1 , акцент мой:

Другом класса является функция или класс, которому предоставлено разрешение на использование закрытых и защищенных имен членов из класса . Класс указывает своих друзей, если таковые имеются, посредством объявлений друзей. Такие объявления дают специальные права доступа друзьям, но они не делают назначенных друзей членами класса дружбы.

Если у вас есть friend E f1(), это дает f1 разрешение на использование личных и защищенных имен из B, в частности. E не является частным или защищенным именем B, это имя, к которому B просто имеет доступ.

<ч />

Концептуально это похоже на [class.friend] / 10 :

Дружба не является ни наследственной, ни переходной.

Поскольку это подразумевает, что правило таково, что f1 может получить доступ к материалам B, а B может получить доступ к материалам A, поэтому f1 может получить доступ к материалам A.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...