С ++ обычный поиск и поиск, зависящий от аргументов

Учитывая этот пример, описанный в http://en.cppreference.com/w/cpp/language/adl:

namespace A {
      struct X;
      struct Y;
      void f(int);
      void g(X);
}

namespace B {
    void f(int i) {
        f(i);   // calls B::f (endless recursion)
    }
    void g(A::X x) {
        g(x);   // Error: ambiguous between B::g (ordinary lookup)
                //        and A::g (argument-dependent lookup)
    }
    void h(A::Y y) {
        h(y);   // calls B::h (endless recursion): ADL examines the A namespace
                // but finds no A::h, so only B::h from ordinary lookup is used
    }
}

Мне интересно, почему возникает двусмысленность, поскольку правила ADL не принимаются во внимание, если

«набор поиска, созданный обычным неквалифицированным поиском, содержит любое из следующего».

Здесь B :: g можно найти с помощью неквалифицированного поиска, как описано в http://en.cppreference.com/w/cpp/language/unqualified_lookup благодаря правилу

Для имени, используемого в определении функции, либо в ее теле, либо как часть аргумента по умолчанию, где функция является членом объявленного пользователем или глобального пространства имен, блок, в котором используется имя, ищется перед использованием имя, затем перед началом этого блока ищется охватывающий блок и т. д., пока не будет достигнут блок, который является телом функции. Затем ищется пространство имен, в котором объявлена ​​функция, до определения (не обязательно объявления) функции, использующей имя, затем охватывающих пространств имен и т. Д.

Тогда у меня вопрос: почему в данном случае рассматриваются правила ADL?


person FlashMcQueen    schedule 01.08.2017    source источник
comment
Не могли бы вы пояснить, почему, по вашему мнению, это не следует принимать во внимание?   -  person cpplearner    schedule 01.08.2017
comment
Во-первых, поиск, зависящий от аргументов, не рассматривается, если набор поиска, созданный обычным неквалифицированным поиском, содержит любое из следующего:   -  person FlashMcQueen    schedule 01.08.2017
comment
1) объявление члена класса 2) объявление функции в области видимости блока (это не объявление-использование) 3) любое объявление, которое не является функцией или шаблоном функции (например, объект функции или другая переменная, имя которой конфликтует с именем искомой функции)   -  person FlashMcQueen    schedule 01.08.2017
comment
Я не вижу ни одного из этих трех в этом фрагменте кода.   -  person cpplearner    schedule 01.08.2017
comment
тогда, если функция, найденная неквалифицированным поиском, найдена, но не в области действия блока, будут учитываться правила ADL?   -  person FlashMcQueen    schedule 01.08.2017


Ответы (2)


Полная цитата

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

  1. объявление члена класса
  2. объявление функции в области видимости блока (это не объявление-использование)
  3. любое объявление, которое не является функцией или шаблоном функции (например, объект функции или другая переменная, имя которой конфликтует с именем функции, которая просматривается)

Это означает, что ADL игнорируется только тогда, когда неквалифицированный поиск дает один из трех результатов выше. Поскольку мы не имеем дело с членом класса, функция объявляется в области пространства имен, а не в области блока, и мы находим только функции, которые продолжаем, и используем ADL.

person NathanOliver    schedule 01.08.2017
comment
Тогда что означает объявление функции в области видимости блока (объявление находится внутри текущей области?) - person FlashMcQueen; 01.08.2017
comment
@FlashMcQueen Это функция, объявленная в области блока - person NathanOliver; 01.08.2017

почему в этом случае рассматриваются правила ADL (поиск, зависимый от аргументов)?

Потому что в связанных пространствах имен могут быть лучшие совпадения. Например.:

void f(void*);

namespace A {
struct X;
void f(X*);
}

int main() {
    A::X* x = 0;
    f(x); // A::f is the best match.
}

Этот механизм часто используется для swap функции:

std::swap может быть специализирован в пространстве имен std для определяемых пользователем типов, но такие специализации не обнаруживаются ADL (пространство имен std не является ассоциированным пространством имен для определяемого пользователем типа). Ожидаемый способ сделать определяемый пользователем тип заменяемым - предоставить замену функции, не являющейся членом, в том же пространстве имен, что и тип: подробности см. в разделе «Замена».

Любое lvalue или rvalue этого типа может быть заменено любым lvalue или rvalue какого-либо другого типа, используя неквалифицированный вызов функции swap() в контексте, где видны как std::swap, так и определяемые пользователем swap().

person Maxim Egorushkin    schedule 01.08.2017