В каких ситуациях срабатывает аргументный поиск по имени (ADL)?

В Статья в википедии ниже цитата упоминается:

ADL происходит только в том случае, если обычный поиск неквалифицированное имя не в состоянии
найти подходящую функцию-член класса. В этом случае, другие пространства имен
не учитывается при обычном поиске, можно искать, где набор
пространства имен для поиска зависит от типа функции
аргументы
.

Итак, я ожидал, что нижеприведенная программа скомпилируется нормально, но это не:

namespace N1 {
class A {};
void foo (A *p) {}
}
namespace N2 {
void foo (N1::A &p) {}
}

int main () {
N1::A xa;
foo(&xa); // ok
foo(xa);  // error: cannot convert ‘N1::A’ to ‘N1::A*’ for argument ‘1’ to ‘void N1::foo(N1::A*)’
}

Я искал несколько вопросов в SO, но не смог найти список требований или ситуаций в простом слове, который предлагает: когда ADL вступает в силу?
Чуть более подробный ответ будет очень полезен для меня и будущих посетителей.

0

Решение

Это не должно компилироваться. A находится в пространстве имен N1, Как компилятор должен знать, что вы хотите вызвать N2::foo?
n3376 3.4.2 / 2


Для каждого типа аргумента T в вызове функции существует набор из нуля или более связанных пространств имен и
набор из нуля или более связанных классов для рассмотрения. Наборы пространств имен и классов определяются
полностью типами аргументов функции (и пространством имен любого аргумента шаблона шаблона).

Имена типов и объявления-использования, используемые для указания типов, не участвуют в этом наборе. Наборы
Пространства имен и классы определяются следующим образом:

Если T является типом класса (включая объединения), его ассоциированными классами являются: сам класс; класс которого это
член, если есть; и его прямые и косвенные базовые классы. Его связанные пространства имен являются пространствами имен
членами которого являются связанные с ним классы.
Кроме того, если T является специализацией шаблона класса,
связанные с ним пространства имен и классы также включают в себя: пространства имен и классы, связанные с
типы аргументов шаблона, предоставляемые для параметров типа шаблона (кроме шаблона шаблона)
параметры); пространства имен, членами которых являются любые аргументы шаблона шаблона; и классы
членами которого являются любые шаблоны элементов, используемые в качестве аргументов шаблонов. [Примечание: не тип
Аргументы шаблона не вносят вклад в набор связанных пространств имен. — конец примечания]

4

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

ADL включается почти всегда, как только ваша функция принимает пользовательский тип. Это начинает foo Вот: xa определяется в N1, так foo ищется в N1 а также в глобальном пространстве имен. (Без ADL, foo будет искать только в глобальном пространстве имен.)

И я не понимаю, почему вы ожидаете второго звонка foo Скомпилировать. Тип xa определяется в N1так ADL добавляет N1 к пути поиска, но в выражении нет ничего, что могло бы подразумевать N2,

1

Это говорит, что «другие пространства имен» ищутся. Это не говорит, что «все пространства имен» ищутся.

Правила для того, что дополнительные пространства имен включены в ADL, немного сложны, но наиболее важным является пространство имен, в котором A определено. Вот почему ваш первый foo найден. Ваш второй foo не может быть найден, потому что пространство имен N2 не имеет ничего общего с ADL.

1

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

пример

func(A x);

Затем компилятор будет смотреть на пространство имен, начиная с пространства имен, включая класс А. Один из примеров:

// argument_dependent_name_koenig_lookup_on_functions.cpp
namespace A
{
struct X
{
};
void f(const X&)
{
}
}
int main()
{
// The compiler finds A::f() in namespace A, which is where
// the type of argument x is defined. The type of x is A::X.
A::X x;
f(x);
}

Больше здесь
http://msdn.microsoft.com/en-us/library/60bx1ys7.aspx

1

Компилятор останавливает поиск, как только он нашел функцию с соответствующим название. Он не продолжает поиск, если типы аргументов или специальные возможности (общедоступные / защищенные / приватные) фактически не позволяют использовать функцию в текущем контексте. Следовательно, в вашем примере компилятор не имеет изменений, чтобы «увидеть» N2::foo, поскольку N1::foo найден первым

Обратите внимание, что в вашем примере N2::foo не будет найден, даже если N1::foo не существует, так как у вас нет ссылки на N2 где-нибудь внутри main, так N2 не будет искать вообще.

0