Исключение поиска друга из шаблона-id?

Рассмотрим следующее предложение в [namespace.memdef]/3:

Если имя в объявлении friend не является ни либо идентификатор шаблона, а декларация - это функция или специфицированный тип-спецификатор, поиск для определения того, был ли объект ранее объявлен, не должен рассматривать какие-либо области вне самого внутреннего охватывающее пространство имен.

Есть ли причина для исключения для идентификатора шаблона вместе с квалифицированным именем? В этом случае существует ли причина для поиска неквалифицированного имени, которое не является идентификатором шаблона, которое должно быть ограничено самым внутренним охватывающим пространством имен? Существует ли конкретная проблема или прецедент, разрешающий это предложение?

Ответы

Ответ 1

Почему ограничение не распространяется на квалифицированные имена и шаблоны?

Квалифицированные имена и шаблоны-идентификаторы не могут вводить новые члены в охватываемое пространство имен, это то, что пытается заметить примечание в [namespace.memdef] p3:

[Примечание. Другие формы объявлений friend не могут объявить новый член самого внутреннего охватывающего пространства имен и, следовательно, следуют обычным правила поиска. - конечная нота]

Следовательно, такое ограничение не требуется для квалифицированных имен и шаблонов-идентификаторов.

Обратите внимание, что в шаблонах-идентификатора отсутствует объявление параметров шаблона, а квалифицированные идентификаторы могут вводить имена в удаленные, несвязанные пространства имен.


Почему вообще существует ограничение?

Эта часть ответа по-прежнему неполна, но представляет собой текущее состояние "исследования". Не стесняйтесь вносить свой вклад.

Ограничение было (возможно?) введено из-за N0783 - Проблемы пространства имен и предлагаемые резолюции, который "пытается прояснить ряд проблем с пространством имен которые в настоящее время либо undefined, либо не полностью указаны".

В этом документе за 1995 год содержится два просветительских обсуждения вопросов, связанных с декларациями субъектов, представленных через объявления друзей. Имейте в виду, что правила поиска имени тогда были разными:

  • Аргумент-зависимый поиск еще не был введен (*)
  • Имена, введенные через объявления-друга, не найдены через чистый неквалифицированный поиск (без ADL) в соответствии с текущими правилами, см. [namespace.memdef] p3 и CWG 1477. Примеры из N0878 предполагают, что эти имена можно было найти через чистый неквалифицированный поиск в то время.

(*) Лучшее, что я мог найти, было N0878 с марта 1996 года, в котором говорится: "Изменение недавно был добавлен в рабочий документ, чтобы добавить" правило поиска Koenig ""

Во-первых, пример из N0783 для функций:

void f(char);

namespace A {
    class B {
        friend void f(char);   // ::f(char) is a friend
        friend void f(int);    // A::f(int) is a friend

        void bf();
    };
    void B::bf()
    {
        f(1);  // calls A::f(int);
        f('x');  // also calls A::f(int) because ::f is hidden
    }
}

Вторая декларация друга должна ввести новую функцию. N0783 пытается указать, в какой области применения это объявление введено. Это предполагает

Все объявления друзей для данного имени должны объявлять объекты в одном конкретный объем.

как правило, чтобы избежать неожиданностей ситуаций, таких как выше.

Итак, вопрос в том, в какой области они объявляют объекты? Есть две возможности, либо

  • При поиске предыдущего объявления функции просмотрите до ближайшего охватывающего пространства имен или
  • При поиске предыдущего объявления просмотрите все охватывающие области для имени объявленной функции. Если предыдущий использование имени найдено, объявление вводится в эту область. Если предыдущее использование имени не найдено, друг вводится в ближайшая закрывающая область пространства имен.

Правило № 2 означает, что наличие любой функции, называемой f в охватывающий объем, независимо от того, совпадают ли типы, было бы достаточно для вызвать объявление друга в эту область.

Я считаю, что правило № 2 явно неприемлемо. Объявление друга в пространстве имен будет затронута любая глобальная декларация этого имя. Подумайте, что это будет означать для операторных функций! наличие какой-либо функции operator+ в глобальном масштабе все друзья operator+ появятся в глобальной области тоже! Наличие шаблона в глобальном масштабе будет иметь одинаковый эффект.

Для типов классов:

namespace N {
    class A { void f(); };
}

using namespace N;

namespace M {
    class B {
        friend class A;  // Without this rule
                         // makes N::A a friend
        B();
    };
    class A { void f(); };
}

void N::A::f() { M::B  b; }  // A friend under current rules

void M::A::f() { M::B  b; }  // A friend under proposed rules

Оба примера не так интересны в соответствии с текущими правилами, потому что имена, введенные через объявления друзей, встречаются только через ADL. Возможно, это ограничение является историческим артефактом. Требуется дальнейшее "исследование", чтобы следить за развитием этого ограничения после введения ADL.