Подтвердить что ты не робот

Как объектные объекты влияют на разрешение перегрузки?

Являются ли объектные объекты обработаны по-разному по сравнению с регулярными функциями при разрешении перегрузки? Если да, то как?

Я столкнулся с следующим случаем: замена функции эквивалентным образом вызываемым объектом функции изменила значение кода:

#include <iostream>

namespace N
{
    enum E { A, B };

    void bar(E mode) { std::cout << "N::bar\n"; }
}

template <typename... Args>
void bar(Args&&... args) { std::cout << "global bar\n"; }

int main()
{
    bar(N::A);
}

Здесь вывод "N:: bar". Пока что так хорошо: N:: bar найден ADL, как N:: bar, так и глобальная строка являются точными совпадениями, а N:: bar предпочтительнее, потому что это не шаблон.

Но если я изменяю глобальный бар как объект функции, например:

#include <iostream>

namespace N
{
    enum E { A, B };

    void bar(E mode) { std::cout << "N::bar\n"; }
}

struct S
{
    template <typename... Args>
    void operator()(Args&&... args) { std::cout << "global bar\n"; }
};
S bar;

int main()
{
    bar(N::A);
}

Выход теперь "глобальная строка". Почему разница?

4b9b3361

Ответ 1

Важным здесь является то, что ADL запускается только в том случае, если lookup определяет, что имя является функцией в вызове функции. Во втором случае bar оказывается объектом, а не функцией, поэтому выражение bar(N::A) не является вызовом функции, а приложение operator() к объекту bar. Поскольку это не вызов функции, ADL не работает, а N::bar не рассматривается.

3.4.1/3

Поиск неквалифицированного имени, используемого как постфиксное выражение вызова функции, описан в 3.4.2. [Примечание. Для определения (во время разбора), является ли выражение постфиксным выражением для функционального вызова, применяются обычные правила поиска имен. Правила в 3.4.2 [ADL] не влияют на синтаксическую интерпретацию выражения.

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

Ответ 2

См. 3.4.2p3, в котором говорится

Пусть X - это набор поиска, созданный неквалифицированным поиском (3.4.1), и Y - это набор поиска, созданный зависимым от аргумента поиска (определяется следующим образом). Если X содержит

  • ...
  • объявление, которое не является ни функцией, ни шаблоном функции

тогда Y пусто.

Если такого правила не будет, вы правы: ADL добавит вашу другую функцию в набор перегрузки. Фактически, 13.3.1.1p1 полагается на это: он имеет две ветки; один для выражений вызова функции, где операнд обозначает объект класса, а другой - операнд, обозначающий одну или несколько функций или шаблонов функций.