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

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 ]

4 голосов
/ 20 февраля 2020

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

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

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

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

2 голосов
/ 20 февраля 2020

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

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

#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 ++ некоторых новых понятий.

...