Подтвердить что ты не робот

Объявление класса друга и использование директивы

Является ли следующий пример корректным?

namespace N {
    class A;
}
using namespace N;

class B {
    int i;
    friend class A;
};

namespace N {
    class A {
        B m;
        int get() { return m.i; }
    };
}

Этот пример успешно скомпилирован с Clang 3.5, но не с g++ 4.8.1 со следующим:

main.cpp: In member function ‘int N::A::get()’:
main.cpp:7:9: error: ‘int B::i’ is private
     int i;
         ^
main.cpp:14:30: error: within this context
         int get() { return m.i; }
                              ^

С++ 11 standard §7.3.1.2 p3 говорит,

Если имя в объявлении friend не является ни квалифицированным, ни идентификатором шаблона, а декларация является функцией или специфицированным спецификатором типа, поиск для определения того, был ли объект ранее объявлен, не должен рассматривать какие-либо области вне самого внутреннего охватывающего пространства имен.

В примере class A не входит в внутреннее пространство имен (т.е. глобальное пространство имен), но class A вводится с помощью директивы в глобальное пространство имен.

4b9b3361

Ответ 1

При использовании пространства имен N вытаскивает имя N:: A в глобальное пространство имен, оно не объявляет, что A в глобальном пространстве имен. Следовательно, дополнительный A в глобальном пространстве имен является другом B. clang неправильно.

Ответ 2

Чтобы сделать N::A без квалификации a friend of B, вы должны использовать

friend A;

а не

friend class A;

При использовании специфицированного спецификатора типа, т.е. class A, и он находится в этой конкретной форме, он вводит имя класса (см. 3.4.4 [basic.lookup.elab], пункт 2).