Какое полное имя функции-друга определено внутри класса?
Недавно я увидел пример, аналогичный следующему. Что такое полное имя val()
ниже?
#include <iostream>
namespace foo {
class A {
int x;
public:
A(int x = 0) : x(x) { }
friend int val(const A &a) { return a.x; }
};
}
int main() {
foo::A a(42);
// val() found using ADL:
std::cout << val(a) << std::endl;
// foo::val(a); // error: 'val' is not a member of 'foo'
// foo::A::val(a); // error: 'val' is not a member of 'foo::A'
return 0;
}
Является ли аргумент-зависимый поиск единственным способом val()
может быть найден?
Следует признать, что это не связано с практической проблемой. Я просто ищу лучшего понимания.
Является ли зависимый от аргумента поиск единственным способом найти val ()?
Да, это единственный способ. Цитировать священный стандарт в [Namespace.memdef] / 3:
Если объявление друга в нелокальном классе сначала объявляет класс,
функция, шаблон класса или шаблон функции друг является членом
внутреннего вложенного пространства имен. Декларация друга не
Само по себе делает имя видимым для неквалифицированного или квалифицированного поиска.
Так что пока val
является членом foo
, это не видно для поиска из декларации друга в одиночку. Внешнее определение (которое также является объявлением) требуется, чтобы сделать его видимым. Для встроенного определения (и без объявления вне класса) это означает, что ADL — единственный способ вызвать функцию.
В качестве дополнительного бонуса, C ++ когда-то имел концепцию «инъекция имени друга». Это однако было удалено, и правила для ADL приспособлены как замена. Более подробный обзор можно найти в документе WG21 N0777 (PDF).
Стандарт C ++ [7.3.1.2/3 (ISO / IEC 14882: 2011)]:
Каждое имя, впервые объявленное в пространстве имен, является членом этого
Пространство имен. Если объявление друга в нелокальном классе сначала объявляет
класс или функция друг класс или функция является членом
внутреннее пространство имен. Имя друга не найдено
неквалифицированный поиск (3.4.1) или квалифицированный поиск (3.4.3) до
соответствующее объявление предоставляется в этой области пространства имен (либо
до или после определения класса предоставления дружбы). Если друг
функция вызывается, ее имя может быть найдено путем поиска имени, что
рассматривает функции из пространств имен и классов, связанных с
типы аргументов функции (3.4.2). Если имя у друга
объявление не является ни квалифицированным, ни идентификатором шаблона, ни объявлением
является функцией или подробным спецификатором типа, поиск для определения
был ли объект ранее объявлен не должен рассматривать какие-либо
области видимости за пределами самого внутреннего вмещающего пространства имен.