В Статья в википедии ниже цитата упоминается:
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 вступает в силу?
Чуть более подробный ответ будет очень полезен для меня и будущих посетителей.
Это не должно компилироваться. A
находится в пространстве имен N1
, Как компилятор должен знать, что вы хотите вызвать N2::foo
?
n3376 3.4.2 / 2
Для каждого типа аргумента T в вызове функции существует набор из нуля или более связанных пространств имен и
набор из нуля или более связанных классов для рассмотрения. Наборы пространств имен и классов определяются
полностью типами аргументов функции (и пространством имен любого аргумента шаблона шаблона).
Имена типов и объявления-использования, используемые для указания типов, не участвуют в этом наборе. Наборы
Пространства имен и классы определяются следующим образом:Если T является типом класса (включая объединения), его ассоциированными классами являются: сам класс; класс которого это
член, если есть; и его прямые и косвенные базовые классы. Его связанные пространства имен являются пространствами имен
членами которого являются связанные с ним классы. Кроме того, если T является специализацией шаблона класса,
связанные с ним пространства имен и классы также включают в себя: пространства имен и классы, связанные с
типы аргументов шаблона, предоставляемые для параметров типа шаблона (кроме шаблона шаблона)
параметры); пространства имен, членами которых являются любые аргументы шаблона шаблона; и классы
членами которого являются любые шаблоны элементов, используемые в качестве аргументов шаблонов. [Примечание: не тип
Аргументы шаблона не вносят вклад в набор связанных пространств имен. — конец примечания]
ADL включается почти всегда, как только ваша функция принимает пользовательский тип. Это начинает foo
Вот: xa
определяется в N1
, так foo
ищется в N1
а также в глобальном пространстве имен. (Без ADL, foo
будет искать только в глобальном пространстве имен.)
И я не понимаю, почему вы ожидаете второго звонка foo
Скомпилировать. Тип xa
определяется в N1
так ADL добавляет N1
к пути поиска, но в выражении нет ничего, что могло бы подразумевать N2
,
Это говорит, что «другие пространства имен» ищутся. Это не говорит, что «все пространства имен» ищутся.
Правила для того, что дополнительные пространства имен включены в ADL, немного сложны, но наиболее важным является пространство имен, в котором A
определено. Вот почему ваш первый foo
найден. Ваш второй foo
не может быть найден, потому что пространство имен N2
не имеет ничего общего с ADL.
Если поиск по имени не дает результатов, поиск продолжается с использованием аргумента вызова функции.
пример
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
Компилятор останавливает поиск, как только он нашел функцию с соответствующим название. Он не продолжает поиск, если типы аргументов или специальные возможности (общедоступные / защищенные / приватные) фактически не позволяют использовать функцию в текущем контексте. Следовательно, в вашем примере компилятор не имеет изменений, чтобы «увидеть» N2::foo
, поскольку N1::foo
найден первым
Обратите внимание, что в вашем примере N2::foo
не будет найден, даже если N1::foo
не существует, так как у вас нет ссылки на N2
где-нибудь внутри main
, так N2
не будет искать вообще.