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, Эндрю Кениг.
читайте далее:
стандартный C++03/11 [basic.уважать.argdep]: 3.4.2 поиск имени, зависящего от аргумента.
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