§7.3.1.2/3 в стандарте С++ 11 (акцент мой):
Каждое имя first, объявленное в пространстве имен, является членом этого Пространство имен. Если объявление друга в нелокальном классе first объявляет класс или функция, класс или функция друга является членом внутреннее пространство имен. Имя друга не найдено безоговорочный поиск (3.4.1) или квалифицированный поиск (3.4.3), пока в этой области пространства имен (или до или после определения класса, дающего дружбу). Если друг вызывается функция, ее имя может быть найдено по имени, которое рассматривает функции из пространств имен и классов, связанных с типы аргументов функции (3.4.2). Если имя в другом объявление не является ни квалифицированным, ни идентификатором шаблона, а декларация это функция или специфицированный тип-спецификатор, поиск для определения был ли объект ранее объявлен, не рассматривает области вне самого внутреннего охватывающего пространства имен. [Примечание: другое формы объявлений друзей не могут объявить нового члена внутреннее пространство имен и, следовательно, следовать обычным правилам поиска.
Пример:
// Assume f and g have not yet been defined. void h(int); template <class T> void f2(T); namespace A { class X { friend void f(X); // A::f(X) is a friend class Y { friend void g(); // A::g is a friend friend void h(int); // A::h is a friend // ::h not considered friend void f2<>(int); // ::f2<>(int) is a friend }; }; // A::f, A::g and A::h are not visible here X x; void g() { f(x); } // definition of A::g void f(X) { /* ... */} // definition of A::f void h(int) { /* ... */ } // definition of A::h // A::f, A::g and A::h are visible here and known to be friends } using A::x; void h() { A::f(x); A::X::f(x); // error: f is not a member of A::X A::X::Y::g(); // error: g is not a member of A::X::Y }
Если мне что-то не хватает, я не понимаю необходимости в словах first выше. Насколько я могу судить, вы не можете иметь более одного объявления какого-либо объекта в пространстве имен и не более одного объявления функции друга в классе.
Кроме того, какова актуальность комментария "Предположим, что f и g еще не определены" в примере? На самом деле не имеет значения, объявлены ли эти функции перед определением пространства имен A. Они обязательно будут принадлежать глобальному пространству имен, и они не будут иметь ничего общего с функциями, объявленными внутри пространства имен A.
Edit:
Тот факт, что можно повторять декларации одной и той же функции или декларации и определения функции в пространстве имен, не отменяет моего наблюдения, что использование слов first в §7.3.1.2/3 не нужны.
Edit1
Я только что нашел еще одну ошибку. Комментарий ::f2<>(int) is a friend
неверен. Не только определение функции шаблона f2(T)
в пространстве имен A, но более важно, объявление template <class T> void f2(T);
должно быть внутри A, в противном случае функция f2<>(int)
не будет другом класс A::X::Y
.