Правильно ли сформирован следующий пример?
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; }
^
Стандарт C ++ 11 §7.3.1.2 p3 говорит,
Если имя в
friend
декларация не является ни квалифицированной, ни Шаблон-идентификатор и объявление является функцией или уточненный тип Спецификатор, поиск, чтобы определить, был ли объект ранее объявлен, не должен рассматривать какие-либо области за пределами самого внутреннего окружающего пространства имен.
В примере class A
не является членом внутреннее пространство имен (то есть глобальное пространство имен), но class A
вводится с помощью директивы в глобальном пространстве имен.
Хотя использование пространства имен N приводит к вытягиванию имени N :: A в глобальное пространство имен, оно не объявляет, что A в глобальном пространстве имен. Следовательно, дополнительный A в глобальном пространстве имен является другом B. clang не прав.
Делать N::A
без квалификации friend
из B
вы бы использовали
friend A;
скорее, чем
friend class A;
При использовании разработанного спецификатора типа, т.е. class A
и именно в этой конкретной форме он вводит имя класса (см. 3.4.4 [basic.lookup.elab] параграф 2).