Каким образом компилятор найти шаблон функции X::Макс(Т как const&, Т как const&) через АДЛ в приведенном ниже коде?
Ценится цитата из стандарта.
#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.отдел.кандидат]
1 для вызова функции, где постфиксное выражение является зависимым именем, функции-кандидаты определяются с помощью обычных правил поиска (3.4.1, 3.4.2) за исключением это:
- для части поиска, использующей неполный поиск имен (3.4.1), только объявления функций из определения шаблона контекст найден.
- для части поиска, использующей связанный пространства имен (3.4.2), только объявления функций, найденные в контекст определения шаблона или контекст создания экземпляра шаблона являются найдено.
Неквалифицированный поиск определяется с помощью
3.4.1 неполный поиск имени [основной.уважать.unqual]
1 во всех случаях, перечисленных в 3.4.1, области поиска находятся в состоянии декларации в порядке, указанном в каждой из соответствующих категорий; поиск имени заканчивается, как только объявление найдено для имени. Если нет декларация найдена, программа плохо сформирована.
И зависимый от аргумента поиск (ADL) как
3.4.2 поиск имени, зависящего от аргумента [basic.уважать.аргдеп]
1 Когда постфиксное выражение в вызове функции (5.2.2) является unqualified-id , другие пространства имен, не рассматриваемые во время обычного неквалифицированный поиск (3.4.1) может выполняться и в этих пространствах имен., пространство имен-область действия функции друг или шаблон функции объявления (11.3) не может быть найдено ничего другого видимого. Эти модификации к Поиск зависит от типов аргументов (и для шаблона template аргументы, пространство имен шаблона аргумент).
Почему ваш код терпит неудачу
В вашем примере unqualified lookup и 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); }
Живой пример это печатает "не-шаблон" дважды.