Как компилятор находит функцию шаблона X::max(T const&, T const&) через ADL в приведенном ниже коде?
Цитата из стандарта приветствуется.
#include <iostream>
namespace X {
class A {};
}
template <typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
return max(max(a, b), c);
}
inline X::A const& max(X::A const& a, X::A const& b)
{
std::cout << "non-template" << '\n';
return a;
}
int main()
{
X::A a, b, c;
max(a, b, c);
}
namespace X {
template <typename T>
inline T const& max(T const& a, T const& b)
{
std::cout << "template" << '\n';
return a;
}
}
1 ответ
Standardese
Призыв к max()
в примере влечет за собой зависимое имя, потому что его аргументы зависят от параметра шаблона T
, Двухфазный поиск имен для таких зависимых имен определяется в Стандарте следующим образом:
14.6.4.2 Функции-кандидаты [temp.dep.candidate]
1 Для вызова функции, где выражение post-x-x является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска (3.4.1, 3.4.2), за исключением того, что:
- Для части поиска, использующей неполный поиск имени (3.4.1), найдены только объявления функций из контекста определения шаблона.
- Для части поиска, использующей связанные пространства имен (3.4.2), найдены только объявления функций, найденные либо в контексте определения шаблона, либо в контексте создания шаблона.
Неквалифицированный поиск определяется
3.4.1 Поиск по имени без определения [basic.lookup.unqual]
1 Во всех случаях, перечисленных в п. 3.4.1, выполняется поиск декларации в порядке, указанном в каждой из соответствующих категорий; поиск имени заканчивается, как только для имени найдено объявление. Если декларация не найдена, программа некорректна.
и аргумент-зависимый поиск (ADL) как
3.4.2 Поиск имени в зависимости от аргумента [basic.lookup.argdep]
1 Когда постфиксное выражение в вызове функции (5.2.2) является безусловным идентификатором, можно искать другие пространства имен, не учитываемые при обычном неквалифицированном поиске (3.4.1), и в этих пространствах имен функция друга области пространства имен или Можно найти объявления шаблона функции (11.3), которые не видны иначе. Эти модификации поиска зависят от типов аргументов (и для аргументов шаблона шаблона - пространства имен аргумента шаблона).
Почему ваш код не работает
В вашем примере, неквалифицированный поиск и ADL не обнаруживают перегрузки в точке определения, потому что компилятор не видел двух аргументов max()
еще. ADL также применяется в момент создания экземпляра, и в то время компилятор видел два аргумента template max(T, T)
который единственный, кого можно назвать. (разница в том, что создание шаблона происходит после того, как весь модуль перевода был проанализирован).
Лучше код
Вы должны исправить свой код, поставив не шаблон max(X::A, X::A)
перегрузка внутри namespace X
и переместить template max(T, T)
из этого.
#include <iostream>
// generic code
template <typename T>
inline T const& max(T const& a, T const& b)
{
std::cout << "template" << '\n';
return a;
}
template <typename T>
inline T const& max(T const& a, T const& b, T const& c)
{
using ::max; // fallback if no user-defined max
return max(max(a, b), c);
}
// X specific code
namespace X {
class A {};
inline X::A const& max(X::A const& a, X::A const& b)
{
std::cout << "non-template" << '\n';
return a;
}
} // namespace X
int main()
{
X::A a, b, c;
max(a, b, c);
}
Live-пример, который печатает "не шаблон" дважды.