и тому подобное будет гораздо менее полезным, чем раньше. По крайней мере, если я правильно понял.

авно обнаружил, что декларации друзейчрезвычайно своеобразные правила - если у тебя есть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
}

Если вы посмотрите на стандарт (см.связанный ответ$10чрезвычайно своеобразные правила11$

требующий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, но немедленно перестает играть глупо, когда вы пытаетесь предоставить противоречивую декларацию.

Ответы на вопрос(1)

Ваш ответ на вопрос