Поиск имени, зависящий от аргумента

В языке программирования C++ , зависимый от аргументов поиск ( ADL ) или зависимый от аргументов поиск имени [ 1] применяется к поиску неквалифицированного имени функции в зависимости от типов аргументов , переданных вызову функции . Это поведение также известно как поиск по Кенигу , поскольку его часто приписывают Эндрю Кенигу , хотя он не является его изобретателем. [2]

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

Пример

Пример ADL выглядит так:

пространство имен NS {  класс А {};  void f ( A & a , int i ) {}     } // пространство имен NS int main () { NS :: A a ; f ( a , 0 ); // Вызывает NS::f. }       

Даже несмотря на то, чтоосновнойфункция не находится в пространстве имен NS, и пространство имен NS не находится в области действия, функцияNS::f(A&, целое)обнаруживается из-за объявленных типов фактических аргументов в операторе вызова функции.

Распространенный шаблон в стандартной библиотеке C++ — объявлять перегруженные операторы, которые будут найдены таким образом. Например, эта простая программа Hello World не скомпилировалась бы, если бы не ADL:

#include <iostream> #include <string>  int main () { std :: string str = "привет мир" ; std :: cout << str ; }         

Использование <<эквивалентно вызову operator<<без std::квалификатора. Однако в этом случае перегрузка оператора <<, которая работает для , stringнаходится в stdпространстве имен, поэтому для ее использования требуется ADL.

Следующий код будет работать без ADL (который к нему в любом случае применяется):

#include <iostream> int main () { std :: cout << 5 ; }     

Это работает, потому что оператор вывода для целых чисел является функцией-членом класса std::ostream, который является типом cout. Таким образом, компилятор интерпретирует это выражение как

std :: cout . оператор << ( 5 );

которые он может разрешить во время обычного поиска. Однако учтите, что, например, const char *перегруженная функция operator<<не является функцией-членом в stdпространстве имен и, таким образом, требует ADL для корректного поиска:

/* выведет предоставленную строку символов, как и ожидалось, с помощью ADL, полученного из типа аргумента std::cout */ оператор << ( std :: cout , "Привет" ) /* вызывает функцию-член ostream оператора <<, принимая void const*, которая выведет адрес предоставленной строки символов вместо содержимого строки символов */ std :: cout . Operator << ( "Привет" ) 

Другим примером является перегруженная функция , stdне являющаяся членом пространства имен, operator<<для обработки строк:

/*эквивалентно оператору <<(std::cout, str). Компилятор выполняет поиск в пространстве имен std с помощью ADL из-за типа std::string параметра str и std::cout */ std :: cout << str ;  

Как отмечает Кёниг в личной заметке [2] , без ADL компилятор выдал бы ошибку, сообщающую о том, что он не может найти operator<<, поскольку в операторе явно не указано, что он найден в stdпространстве имен.

Интерфейсы

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

Критика

Хотя ADL делает практичным для функций, определенных вне класса, вести себя так, как будто они являются частью интерфейса этого класса, он делает пространства имен менее строгими и поэтому может потребовать использования полностью определенных имен, когда они в противном случае не были бы нужны. Например, стандартная библиотека C++ широко использует неопределенные вызовы для std::swapобмена двух значений. Идея заключается в том, что затем можно определить собственную версию swapв собственном пространстве имен, и она будет использоваться в алгоритмах стандартной библиотеки. Другими словами, поведение

пространство имен N {  структура А {};  } // пространство имен N А а ; А б ;  std :: swap ( a , b ); 

может быть или не быть таким же, как поведение

использование std :: swap ; swap ( a , b );  

(где aи bимеют тип N::A), потому что если N::swap(N::A&, N::A&)существует, то второй из приведенных выше примеров вызовет его, а первый — нет. Более того, если по какой-то причине определены оба N::swap(N::A&, N::A&)и , то первый пример вызовет , но второй не скомпилируется, потому что это будет неоднозначно.std::swap(N::A&, N::A&)std::swap(N::A&, N::A&)swap(a, b)

В общем, чрезмерная зависимость от ADL может привести к семантическим проблемам. Если одна библиотека, L1, ожидает, что неквалифицированные вызовы будут foo(T)иметь одно значение, а другая библиотека, L2ожидает, что будет иметь другое, то пространства имен теряют свою полезность. Если же L1ожидает , L1::foo(T)что будет иметь одно значение и L2делает то же самое, то конфликта нет, но вызовы foo(T)должны быть полностью квалифицированными (т. е. L1::foo(x)в отличие от using L1::foo; foo(x);), чтобы ADL не мешал.

Ссылки

  1. ^ "Рабочий проект, стандарт языка программирования C++" (PDF) . JTC1/SC22/WG21 . 19 октября 2005 г. Глава 3.4.2 – Поиск имени, зависящий от аргумента – стр. 2. Архивировано из оригинала (PDF) 14 декабря 2005 г. . Получено 13 марта 2012 г. .
  2. ^ ab "Личная заметка о поиске, зависящем от аргумента". 3 мая 2012 г. Архивировано из оригинала 17 марта 2018 г. Получено 7 февраля 2014 г.
  • Поиск, зависящий от аргумента
  • Что входит в класс? – Принцип интерфейса Герба Саттера
  • Пространства имен и принцип интерфейса Герба Саттера
  • Почему я ненавижу пространства имен Дэнни Калева
  • «Скромное предложение: исправление ADL (редакция 2)» Герба Саттера
Получено с "https://en.wikipedia.org/w/index.php?title=Argument-dependent_name_lookup&oldid=1208394140"