Каким образом компилятор найти шаблон функции 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 5

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);
}

Живой пример это печатает "не-шаблон" дважды.