Принятый ответ, к сожалению, вводит в заблуждение.
Разрешение перегрузки для оператора ==
, используемого внутри std::find
шаблона функции, выполняется как при обычном поиске, так и в зависимости от аргументов (ADL)
Регулярный поиск выполняется в соответствии с обычными правилами поиска безоговорочного имени.Это ищется из определения std::find
в стандартной библиотеке.Очевидно, что предоставленное пользователем объявление operator ==
оттуда не видно.
ADL - это отдельная история.Теоретически ADL может видеть имена, определенные позже, например, имена, видимые с точки вызова std::find
внутри main
.Однако ADL не просто видит все.ADL ограничен поиском только внутри так называемых связанных пространств имен .Эти пространства имен вводятся в рассмотрение по типам аргументов, используемых при вызове оператора ==
в соответствии с правилами 6.4.2 / 2 .
. В этом примере типы обоихаргументы ==
принадлежат пространству имен std
.Один аргумент шаблона std:pair<>
также взят из std
.Другой тип имеет фундаментальный тип int
, у которого нет ассоциированного пространства имен .Поэтому std
является единственным связанным пространством имен в этом случае.ADL выглядит в std
и только в std
.Вышеуказанное пользовательское объявление operator ==
не найдено, поскольку оно находится в глобальном пространстве имен.
Неверно говорить, что ADL перестает искать после поиска некоторые «другие» определения operator ==
внутри std
.ADL не работает "наизнанку", как часто делают другие формы поиска.ADL ищет в связанных пространствах имен и все.Независимо от того, были ли обнаружены какие-либо другие формы operator ==
в std
или нет, ADL не пытается продолжить поиск в глобальном пространстве имен.Это неверная / вводящая в заблуждение часть принятого ответа.
Вот более компактный пример, иллюстрирующий ту же проблему
namespace N
{
struct S {};
}
template<typename T> void foo(T a)
{
bar(a);
}
void bar(N::S s) {}
int main()
{
N::S a;
foo(a);
}
Обычный поиск не выполняется, поскольку нет bar
заявлено выше foo
.Видя, что bar
вызывается с аргументом типа N::S
, ADL будет искать bar
в связанном пространстве имен N
.Там нет bar
в N
либо.Код плохо сформирован.Обратите внимание, что отсутствие bar
в N
не заставляет ADL расширять поиск в глобальном пространстве имен и находить глобальный bar
.
Довольно просто непреднамеренно изменить набор связанных пространств имен, используемых ADL, поэтому такие проблемы часто возникают и возникают после, казалось бы, невинных и несвязанных изменений в коде.Например, если мы изменим объявление RegPair
следующим образом
enum E { A, B, C };
typedef std::pair<std::string, E> RegPair;
, ошибка внезапно исчезнет.После этого изменения глобальное пространство имен также становится связанным для ADL, наряду с std
, поэтому ADL находит предоставленное пользователем объявление operator ==
.