Стандартный
Вызов max()
в примере влечет за собой зависимое имя, поскольку его аргументы зависят от параметра шаблона T
. Двухэтапный поиск таких зависимых имен определен в Стандарте следующим образом:
14.6.4.2 Функции-кандидаты [temp.dep.candidate]
1 Для вызова функции, где постфиксное выражение является зависимым именем, функции-кандидаты находятся с использованием обычных правил поиска (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-Example, который дважды печатает "не шаблон".
person
TemplateRex
schedule
02.07.2014