Что такое " Поиск, зависящий от аргумента "(он же ADL или"поиск Кенига")?



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



желательно, я хотел бы знать:




  • почему это хорошо?

  • почему это плохо?

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

857   4  

4 ответов:

Koenig Lookup или Аргумент Зависимого Поиска, описывает, как компилятор ищет неполные имена в C++.

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

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

в более простых условиях Николай государств Джосутису1:

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

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

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

MyNamespace::MyClass obj; // global object


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

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

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

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

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

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

Почему критика Koenig lookup?

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

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

std::swap(obj1,obj2);

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

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

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

если существует пространство имен A и если A::obj1,A::obj2 & A::swap() exist тогда второй пример приведет к вызову 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++: учебник и справочник.

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

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

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

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

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

что действительно слишком много набрав и код выглядит действительно некрасиво!

другими словами, при отсутствии поиска Кенига, даже a Привет, Мир программа выглядит сложным.

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

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

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), вызванный таким образом, поскольку поиск зависит от аргумента (точнее, от типа аргумента). С схема была изобретена Эндрю Р. Кенигом, ее также часто называют Koenig lookup.

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

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

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

пример использования boost

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

это привело к двусмысленности, если пользователь использует повышение.библиотека диапазона, потому что оба std::begin Не найдено (АДЛ, используя std::vector) и boost::begin - Это нашли (АДЛ, используя boost::shared_ptr).

Comments

    Ничего не найдено.