Возможно ли иметь функцию, не являющуюся другом, которую можно найти только с помощью ADL?

В C++ есть особенность, заключающаяся в том, что определенные в классе дружественные функции могут быть найдены только с помощью ADL (поиск в зависимости от аргументов):

struct Foo {
    friend void fn(Foo) { } // fn can only be called by ADL, it won't be found by other lookup methods
};

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

(И несколько самоуверенный вопрос: если это невозможно, в чем причина? Неужели это правило "только обнаруживается с помощью ADL" намеренно встроено в язык?)

2 ответа

Решение

Это возможно только для дружественных функций, так как это единственные функции, для которых существует это многословие. И формулировка, которая делает функции невидимыми для обычного поиска имени, и формулировка, которая учитывает их во время ADL, применяется только к таким друзьям.

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

Эта функция должна была быть удалена, но она была основой уловки Бартона-Накмана, и поэтому было предложено решение, которое в конечном итоге стало тем, что мы знаем как встроенные функции друзей, которые ищет только ADL. Он был разработан, чтобы облегчить идиому программирования.

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

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

Вот демонстрационная программа

#include <iostream>

namespace N1
{

struct A
{
    int a = 10;
    friend void f( A &a ) { std::cout << "friend f( A & ) : A::a = " <<  a.a << '\n'; }     
};

void f( const A &a ) { std::cout << "f( const A & ) : A::a = " <<  a.a << '\n'; }   

}            

int main()
{
    N1::A a1;
    f( a1 );

    const N1::A a2;
    f( a2 );

    N1::f( a1 );
}    

Вывод программы

friend f( A & ) : A::a = 10
f( const A & ) : A::a = 10
f( const A & ) : A::a = 10

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

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

Чтобы добиться того же действия с функциями, не являющимися друзьями, вы должны сначала сделать их невидимыми в пространстве имен, где вводятся их объявления, и поиск квалифицированного имени не должен их найти. Это невозможно без введения в Стандарт C++ некоторых новых понятий.

Другие вопросы по тегам