Каковы хорошие объяснения того, что поиск зависит от аргумента? Многие также называют это Koenig Lookup.
Желательно, чтобы я знал:
- Почему это хорошо?
- Почему это плохо?
- Как это работает?
c++
argument-dependent-lookup
name-lookup
c++-faq
user965369
источник
источник
std::cout << "Hello world";
не будет компилироватьсяОтветы:
Koenig Lookup или Argument Dependent Lookup описывает, как неквалифицированные имена ищутся компилятором в C ++.
Стандарт C ++ 11 § 3.4.2 / 1 гласит:
В более простых сроках Николай Josuttis заявляет 1 :
Простой пример кода:
В приведенном выше примере нет ни
using
-declaration, ниusing
-directive, но все же компилятор правильно идентифицирует неквалифицированное имяdoSomething()
как функцию, объявленную в пространстве именMyNamespace
, применяя поиск Кенига .Как это работает?
Алгоритм говорит компилятору не только смотреть на локальную область видимости, но также на пространства имен, которые содержат тип аргумента. Таким образом, в приведенном выше коде компилятор обнаруживает, что объект
obj
, являющийся аргументом функцииdoSomething()
, принадлежит пространству именMyNamespace
. Таким образом, он смотрит на это пространство имен, чтобы найти объявлениеdoSomething()
.В чем преимущество поиска Кенига?
Как показывает приведенный выше пример простого кода, поиск по Кенигу обеспечивает удобство и простоту использования для программиста. Без поиска Кенига программисту потребовалось бы много времени, чтобы многократно указывать полностью определенные имена или вместо этого использовать многочисленные
using
-декларации.Почему критика поиска Кенига?
Чрезмерная зависимость от поиска Кенига может привести к семантическим проблемам и иногда застать программиста врасплох.
Рассмотрим пример
std::swap
, представляющий собой стандартный алгоритм библиотеки для обмена двумя значениями. С поиском Кенига нужно было бы быть осторожным при использовании этого алгоритма, потому что:может не показывать такое же поведение как:
В случае 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 Эндрю Кенигом .
Дальнейшее чтение:
Поиск имени Херба Саттера на GotW
Стандарт C ++ 03/11 [basic.lookup.argdep]: 3.4.2 Поиск имени в зависимости от аргумента.
1 Определение поиска Кенига определено в книге Джозуттиса « Стандартная библиотека C ++: учебное пособие и справочник» .
источник
std::swap
вами на самом деле нужно это сделать, поскольку единственной альтернативой было бы добавитьstd::swap
явную специализацию функции шаблона для вашегоA
класса. Тем не менее, если вашA
класс является самим шаблоном, это будет частичная специализация, а не явная специализация. И частичная специализация шаблонной функции не допускается. Добавление перегрузкиstd::swap
было бы альтернативой, но явно запрещено (вы не можете добавлять вещи вstd
пространство имен). Так что ADL - единственный путьstd::swap
.std::swap()
немного задом наперед. Я ожидаю, что проблема будет, когдаstd::swap()
выбран, а не перегрузка, специфичная для типаA::swap()
. Пример сstd::swap(A::MyClass&, A::MyClass&)
представлением вводит в заблуждение. такstd
как никогда не было бы определенной перегрузки для пользовательского типа, я не думаю, что это отличный пример.MyNamespace::doSomething
, а не только::doSomething
.В Koenig Lookup, если функция вызывается без указания ее пространства имен, тогда имя функции также ищется в пространстве (ах) имен, в котором определен тип аргумента (ов). Вот почему оно также известно как Аргумент-зависимое имя Lookup , короче говоря просто ADL .
Именно из-за поиска Кенига мы можем написать это:
В противном случае мы должны были бы написать:
что на самом деле слишком много печатать, и код выглядит действительно ужасно!
Другими словами, в отсутствие Koenig Lookup даже программа Hello World выглядит сложной.
источник
std::cout
это один аргумент функции, которого достаточно для включения ADL. Вы это заметили?ostream<<
(как в том, что он принимает в качестве аргументов, так и в том, что он возвращает). 2) Полностью квалифицированные имена (например,std::vector
илиstd::operator<<
). 3) Более подробное исследование Argument Dependent Lookup.std::endl
качестве аргумента, на самом деле является функцией-членом. В любом случае, если я использую"\n"
вместоstd::endl
, то мой ответ правильный. Спасибо за комментарий.f(a,b)
вызывает свободную функцию. Так что в случаеstd::operator<<(std::cout, std::endl);
, нет такой свободной функции, которая принимает вstd::endl
качестве второго аргумента. Это функция-член, которая принимает вstd::endl
качестве аргумента и для которой вы должны написатьstd::cout.operator<<(std::endl);
. и так как есть свободная функция, которая принимает вchar const*
качестве второго аргумента,"\n"
работает;'\n'
будет работать так же.Может быть, лучше начать с «почему», и только потом перейти к «как».
Когда были введены пространства имен, идея состояла в том, чтобы все было определено в пространствах имен, чтобы отдельные библиотеки не мешали друг другу. Однако это привело к проблеме с операторами. Посмотрите, например, на следующий код:
Конечно, вы могли бы написать
N::operator++(x)
, но это победило бы весь смысл перегрузки оператора. Следовательно, нужно было найти решение, которое позволило бы найти компилятор,operator++(X&)
несмотря на то, что оно не входило в область видимости. С другой стороны, он по-прежнему не должен находить другое,operator++
определенное в другом, несвязанном пространстве имен, что может сделать вызов неоднозначным (в этом простом примере вы не получите двусмысленности, но в более сложных примерах вы можете). Решением был Аргумент-зависимый поиск (ADL), названный таким образом, поскольку поиск зависит от аргумента (точнее, от типа аргумента). Поскольку схема была изобретена Эндрю Р. Кенигом, ее также часто называют поиском Кенига.Хитрость заключается в том, что для вызовов функций, в дополнение к обычному поиску имен (который находит имена в области действия в момент использования), выполняется второй поиск в областях типов любых аргументов, переданных функции. Таким образом , в приведенном выше примере, если вы пишете
x++
в основном, он ищетoperator++
не только в глобальном масштабе, но , кроме того , в сфере , где типx
,N::X
был определен, то есть вnamespace N
. И там он находит соответствиеoperator++
, и поэтомуx++
просто работает. Однако, другое,operator++
определенное в другом пространстве именN2
, не будет найдено. Поскольку ADL не ограничен пространствами имен, вы также можете использоватьf(x)
вместоN::f(x)
inmain()
.источник
Не все в этом хорошо, на мой взгляд. Люди, включая поставщиков компиляторов, оскорбляли его из-за его иногда неудачного поведения.
ADL отвечает за капитальный ремонт цикла for-range в C ++ 11. Чтобы понять, почему ADL иногда может иметь непреднамеренные эффекты, рассмотрим, что учитываются не только пространства имен, в которых определены аргументы, но также аргументы шаблонных аргументов аргументов, типов параметров типов функций / типов-указателей типов указателей этих аргументов. и так далее и тому подобное.
Пример использования наддува
Это привело к неоднозначности, если пользователь использует библиотеку boost.range, потому что оба
std::begin
найдены (с помощью ADLstd::vector
) иboost::begin
найдены (с помощью ADLboost::shared_ptr
).источник
std::begin
очищает двусмысленность пространства имен.