Поиск имени для перегруженных функций, определенных позже

Я заметил странное поведение в отношении поиска функций, когда полагался на функцию, которая будет определена позже:

#include <iostream>

template <typename T>
void foo(const T&)
{
std::cout << "Basic" << std::endl;
}

template <typename T>
void bar()
{
T x;
foo(x);
}

void foo(const int& x)
{
std::cout << "int:" << x << std::endl;
}

int main()
{
bar<int>();
}

Выход:

Basic

По какой-то причине я ожидал использования foo внутри bar найти перегрузку под ним. Перемещение перегрузки foo выше bar делает вывод желаемым int:0 (или просто написание декларации).

Такое же поведение, похоже, не относится к перегрузке бинарного оператора:

#include <iostream>

struct Foo {} foo;

template <typename T>
void operator<<(const Foo&, const T&)
{
std::cout << "Basic" << std::endl;
}

template <typename T>
void bar()
{
T x;
foo << x;
}

void operator<<(const Foo&, const int& x)
{
std::cout << "int:" << x << std::endl;
}

int main()
{
bar<int>();
}

Выход:

int:0

У меня есть два вопроса, первый: почему такое поведение и почему оно отличается для перегрузки операторов? Второй: если у меня есть именованная функция (например, мое использование foo), есть ли способ написать функцию bar таким способом обнаружить перегруженный foos объявлен позже в переводческой единице?

5

Решение

Добро пожаловать в мир самых известных двухфазных правил поиска и странных правил.

Я уверен, что нет различий в операторах и функциях только за секунду, когда вы использовали еще один аргумент. Попробуйте, что произойдет, если для первой версии вы также добавите еще один параметр со структурой Foo …

Двухфазный поиск означает, что для зависимых имен, когда шаблон компилируется, он просматривает и запоминает набор видимых функций. В вашем случае это ничего не находит. Затем в контексте создания существует другой поиск, следуя правилам ADL (поиск, зависящий от аргумента). Только это. Это означает сначала сбор «связанных пространств имен» аргументов, а затем поиск дополнительных кандидатов в этих пространствах имен.

В вашем случае единственным аргументом является int, и он не имеет связанных пространств имен, поэтому ничего не найдено снова. Во втором случае у вас также есть Foo, который перетаскивает :: с ним, и ваш оператор находится в ::.

2

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

Других решений пока нет …

По вопросам рекламы [email protected]