Что такое «Аргумент-зависимый поиск» (он же ADL или «Поиск Кенига»)?

Каковы хорошие объяснения того, что поиск зависит от аргумента? Многие люди также называют это Koenig Lookup.

Желательно, чтобы я знал:

  • Почему это хорошо?
  • Почему это плохо?
  • Как это работает?

140

Решение

Поиск Кенига, или же Аргумент Зависимый поиск, описывает, как неквалифицированные имена ищутся компилятором в C ++.

Стандарт C ++ 11 § 3.4.2 / 1 гласит:

Когда выражение postfix в вызове функции (5.2.2) является безусловным идентификатором, могут быть найдены другие пространства имен, не учитываемые во время обычного безусловного поиска (3.4.1), и в этих пространствах имен объявления функций друзей области видимости области пространства ( 11.3) может быть найдено не видимое иное. Эти модификации поиска зависят от типов аргументов (а для аргументов шаблона шаблона — пространства имен шаблона).
аргумент).

В более простых сроках Николай Josuttis заявляет1:

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

Простой пример кода:

namespace MyNamespace
{
class MyClass {};
void doSomething(MyClass);
}

MyNamespace::MyClass obj; // global objectint main()
{
doSomething(obj); // Works Fine - MyNamespace::doSomething() is called.
}

В приведенном выше примере нет ни using-декларация ни using-directive, но все же компилятор правильно идентифицирует неквалифицированное имя doSomething() как функция, объявленная в пространстве имен MyNamespace применяя Поиск Кенига.

Как это работает?

Алгоритм говорит компилятору не только смотреть на локальную область видимости, но также на пространства имен, которые содержат тип аргумента. Таким образом, в приведенном выше коде компилятор обнаруживает, что объект obj, который является аргументом функции doSomething()принадлежит к пространству имен MyNamespace, Таким образом, он смотрит на это пространство имен, чтобы найти объявление doSomething(),

В чем преимущество поиска Кенига?

Как показывает приведенный выше пример простого кода, поиск по Кенигу обеспечивает удобство и простоту использования для программиста. Без поиска Кенига программисту потребовалось бы много времени, чтобы повторно указывать полностью определенные имена или вместо этого использовать многочисленные using-declarations.

Почему критика поиска Кенига?

Чрезмерная зависимость от поиска Кенига может привести к семантическим проблемам и иногда застать программиста врасплох.

Рассмотрим пример std::swap, который является стандартным библиотечным алгоритмом для обмена двумя значениями. С поиском Кенига нужно было бы быть осторожным при использовании этого алгоритма, потому что:

std::swap(obj1,obj2);

может не показывать такое же поведение как:

using std::swap;
swap(obj1, obj2);

С ADL, какая версия swap Функция, которая будет вызвана, будет зависеть от пространства имен передаваемых ей аргументов.

Если существует пространство имен A и если A::obj1, A::obj2 & A::swap() существует, тогда второй пример приведет к вызову A::swap(), что может быть не тем, что хотел пользователь.

Далее, если по какой-то причине оба A::swap(A::MyClass&, A::MyClass&) а также std::swap(A::MyClass&, A::MyClass&) определены, то первый пример будет вызывать std::swap(A::MyClass&, A::MyClass&) но второй не скомпилируется, потому что swap(obj1, obj2) было бы неоднозначно.

Общая информация:

Почему это называется «поиск Кенига»?

Потому что он был разработан бывшим AT&Исследователь и программист T & Bell Labs, Эндрю Кениг.

Дальнейшее чтение:



1 Определение поиска Кенига такое же, как в книге Джозуттиса, Стандартная библиотека C ++: учебное пособие и справочник.

187

Другие решения

В Koenig Lookup, если функция вызывается без указания ее пространства имен, тогда имя функции также поиск в пространстве (ах) имен, в котором определен тип аргумента (ов). Вот почему он также известен как Зависимый от аргумента поиск имени, короче просто ADL.

Именно из-за поиска Кенига мы можем написать это:

std::cout << "Hello World!" << "\n";

В противном случае мы должны были бы написать:

std::operator<<(std::operator<<(std::cout, "Hello World!"), "\n");

что на самом деле слишком много печатать, и код выглядит действительно ужасно!

Другими словами, в отсутствие Koenig Lookup даже Привет, мир Программа выглядит сложной.

55

Может быть, лучше начать с «почему», и только потом перейти к «как».

Когда были введены пространства имен, идея состояла в том, чтобы все было определено в пространствах имен, чтобы отдельные библиотеки не мешали друг другу. Однако это привело к проблемам с операторами. Посмотрите, например, на следующий код:

namespace N
{
class X {};
void f(X);
X& operator++(X&);
}

int main()
{
// define an object of type X
N::X x;

// apply f to it
N::f(x);

// apply operator++ to it
???
}

Конечно, вы могли бы написать N::operator++(x), но это победило бы весь смысл перегрузки оператора. Поэтому нужно было найти решение, которое позволило бы компилятору найти operator++(X&) несмотря на то, что это не было в объеме. С другой стороны, он все равно не должен найти другой operator++ определяется в другом, несвязанном пространстве имен, которое может сделать вызов неоднозначным (в этом простом примере вы не получите двусмысленности, но в более сложных примерах вы можете). Решением был Аргумент-зависимый поиск (ADL), названный таким образом, так как поиск зависит от аргумента (точнее, от типа аргумента). Поскольку схема была изобретена Эндрю Р. Кенигом, ее также часто называют поиском Кенига.

Хитрость заключается в том, что для вызовов функций, в дополнение к обычному поиску имен (который находит имена в области действия в момент использования), выполняется второй поиск в областях типов любых аргументов, переданных функции. Так что в приведенном выше примере, если вы пишете x++ в основном это выглядит operator++ не только в глобальном масштабе, но дополнительно в области, где тип x, N::Xбыл определен, то есть в namespace N, И там он находит соответствие operator++, и поэтому x++ просто работает. Другая operator++ определено в другом пространстве имен, скажем N2, не будет найден, однако. Поскольку ADL не ограничен пространствами имен, вы также можете использовать f(x) вместо N::f(x) в main(),

25

Не все в этом хорошо, на мой взгляд. Люди, включая поставщиков компиляторов, оскорбляли его из-за его иногда неудачного поведения.

ADL отвечает за капитальный ремонт цикла for-range в C ++ 11. Чтобы понять, почему ADL иногда может иметь непреднамеренные эффекты, рассмотрим, что учитываются не только пространства имен, в которых определены аргументы, но также аргументы шаблонных аргументов аргументов, типов параметров типов функций / типов-указателей типов указателей этих аргументов. и так далее и тому подобное.

Пример использования наддува

std::vector<boost::shared_ptr<int>> v;
auto x = begin(v);

Это привело к неоднозначности, если пользователь использует библиотеку boost.range, потому что оба std::begin найдено (используя ADL std::vector) а также boost::begin найдено (используя ADL boost::shared_ptr).

19
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector