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
действителен?
Соответствующие Стандартные части, которые я нашел:
Вложенный класс является членом, и поэтому имеет те же права доступа, что и любой другой член.
Хотя это само по себе не означает, что друзья вложенного класса имеют все те же права, что и вложенный класс.
Доступ к члену зависит от класса, в котором он назван. Этот класс именования является классом, в котором имя члена было найдено и найдено. Член
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