Существует перегрузка std::max
, которая выглядит следующим образом (от cppreference.com ):
template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );
Это лучше подходит для вашего звонка auto res = std::max({b}, a);
, чем
template< class T >
constexpr const T& max( const T& a, const T& b );
, который вы пытаетесь вызвать, так как {b}
может быть выведен на std::initializer_list<int>
, и этот вызов имеет ранг преобразования с точным соответствием в обоих аргументах, в то время как перегрузка, которую вы хотите вызвать, требует преобразования от int
до double
, что не является точным соответствием.
Второй аргумент тогда считается функтором Compare
, который вызывается для операции сравнения, но вызов double
явно не удался. Перегрузка не отключается, если второй аргумент не вызывается, поэтому он все еще выбран.
Этого не происходит с auto res = std::max(a, {b});
, потому что нет перегрузки с параметром std::initializer_list
для второго аргумент и так только перегрузка, которую вы хотите вызвать, является жизнеспособным. Список инициализаторов делает второй параметр не выводимым контекстом, поэтому он работает в отличие от auto res = std::max(a, b);
, который завершается ошибкой из-за несоответствия вывода аргументов шаблона между двумя аргументами.