Ответ 1
[n3290: 7.3.1.2/3]:
Каждое имя, впервые объявленное в пространстве имен, является член этого пространства имен. Если объявлениеfriend
в нелокальном классе сначала объявляет класс или функцию, класс или функция друга член самого внутреннего охватывающего пространства имен. Имя друга не найденный неквалифицированным поиском (3.4.1) или квалифицированным поиском (3.4.3) 95) это означает, что имя класса или функции неквалифицированный. пока соответствующая декларация не будет предоставлена в пространство имен (до или после предоставления определения класса дружба). Если вызывается функция друга, ее имя может быть найдено поиск имени, который рассматривает функции из пространств имен и классов связанные с типами аргументов функции (3.4.2). Если имя в объявленииfriend
не является ни квалифицированным, ни идентификатором шаблона и декларация является функцией или специфицированным спецификатором типа, поиск, чтобы определить, было ли ранее объявлено сущность не должны рассматривать какие-либо области вне самого внутреннего пространство имен. [..]
Внутрипространственное пространство имен является анонимным, и вы не определили имя функции, поэтому имя не найдено.
Пространство имен не обязательно должно быть анонимным.
Обратите внимание, что extern "C"
в вопросе - это красная селедка, а по той же причине не работает следующее:
void foo();
namespace {
struct T {
friend void foo();
private: void bar() { cout << "!"; }
} t;
}
void foo() { t.bar(); }
int main() {
foo();
}
/*
In function 'void foo()':
Line 7: error: 'void<unnamed>::T::bar()' is private
compilation terminated due to -Wfatal-errors.
*/
[альтернативный тест, адаптированный из вашего исходного кода]