Подтвердить что ты не робот

Каково полное имя функции друга, определенной внутри класса?

Каково полное имя функции друга, определенной внутри класса?

Недавно я увидел пример, аналогичный приведенному ниже. Каково полное имя 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()?

По общему признанию, это не связано с практической проблемой. Я просто хочу получить лучшее понимание.

4b9b3361

Ответ 1

Является ли зависящий от аргумента поиск единственным способом нахождения val()?

Да, это единственный способ. Чтобы процитировать священный стандарт в [namespace.memdef]/3:

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

Итак, пока val является членом foo, он не отображается для поиска только из декларации друга. Для определения видимости требуется определение класса (которое также является объявлением). Для встроенного определения (и без объявления вне класса) это означает, что ADL - это единственный способ вызвать функцию.


В качестве дополнительного бонуса, С++ однажды получил концепцию "впрыска имени друга". Это, однако, было удалено, а правила для ADL скорректированы как замена. Более подробный обзор можно найти в документе WG21 N0777 (pdf).

Ответ 2

Стандарт С++ [7.3.1.2/3 (ISO/IEC 14882: 2011)]:

Каждое имя, впервые объявленное в пространстве имен, является членом этого Пространство имен. Если объявление друга в нелокальном классе объявляет сначала класс или функция, класс или функция друга является членом внутреннее пространство имен. Имя друга не найдено безоговорочный поиск (3.4.1) или квалифицированный поиск (3.4.3), пока в этой области пространства имен (или до или после определения класса, предоставляющего дружбу). Если друг вызывается функция, ее имя может быть найдено по имени, которое рассматривает функции из пространств имен и классов, связанных с типы аргументов функции (3.4.2). Если имя в другом объявление не является ни квалифицированным, ни идентификатором шаблона, а декларация это функция или специфицированный тип-спецификатор, поиск для определения был ли объект ранее объявлен , не должен области вне самого внутреннего охватывающего пространства имен.