Недавно я обнаружил, что обзор деклараций друзей следует чрезвычайно специфическим правилам - если у вас есть объявление friend
(определение) для функции или класса, который еще не объявлен, он автоматически объявляется (определяется) в непосредственно вложенном пространстве имен, но он невидим к неквалифицированному и квалифицированному поиску; однако объявления функций друга остаются видимыми через зависящий от аргумента поиск.
struct M {
friend void foo();
friend void bar(M);
};
void baz() {
foo(); // error, unqualified lookup cannot find it
::foo(); // error, qualified lookup cannot find it
bar(M()); // ok, thanks to ADL magic
}
Если вы посмотрите на стандарт (см. Связанный ответ), они пошли на значительную длину, чтобы включить это эксцентричное поведение, добавив конкретное исключение в квалифицированный/не квалифицированный поиск со сложными правилами. Конечный результат выглядит очень запутанным 1 с еще одним аргументом в углу, чтобы добавить к реализациям. Как либо
- требуя, чтобы объявления
friend
ссылались на существующие имена, период; или же - позволяя им объявлять материал таким, какой он есть сейчас, но без изменения обычного поиска имен (поэтому такие имена становятся видимыми, как если бы они были объявлены "нормально" в охватывающем пространстве имен)
кажется, проще реализовать, указать и, самое главное, понять, интересно, почему они беспокоились об этом беспорядке? Какие варианты использования они пытались охватить? Что ломается под любым из этих более простых правил (в частности, второе, наиболее похожее на существующее поведение)?
-
Например, в данном конкретном случае
struct M { friend class N; }; N *foo; typedef int N;
вы получаете комически шизофренические сообщения об ошибках
<source>:4:1: error: 'N' does not name a type N *foo; ^ <source>:5:13: error: conflicting declaration 'typedef int N' typedef int N; ^ <source>:2:17: note: previous declaration as 'class N' friend class N; ^
где компилятор сначала утверждает, что нет такой вещи, как
N
, но сразу же перестает играть глупо, когда вы пытаетесь представить противоречивую декларацию.