I am experimenting with std::max. I am tring to pass integers constexpr with uniform initialization (curly braces), to compare them to floating-point variables.
Experiment a): Call std::max() with double/int mixed
double a = 3.0;
int b = 5;
auto res = std::max(a, b);
Does not compile. Clang reports error: no matching function for call to 'max'
. This is of course OK.
Experiment b): Use curly braces + constexpr int for non-anrrowing conversion
double a = 3.0;
constexpr int b = 5;
auto res = std::max(a, {b});
Compiles and works as expected: returns a double with value 5.0.
Experiment c): Same as b) but swap arguments of std::max.
double a = 3.0;
constexpr int b = 5;
auto res = std::max({b}, a);
Does not compile both under gcc and clang. Why?
Clang reports error: called object type 'double' is not a function or function pointer
.
There exists an overload of std::max
that looks like this (from cppreference.com):
template< class T, class Compare >
constexpr T max( std::initializer_list<T> ilist, Compare comp );
This is a better match for your call auto res = std::max({b}, a);
than
template< class T >
constexpr const T& max( const T& a, const T& b );
which you are trying to call, since the {b}
can be deduced to std::initializer_list<int>
and that call has exact match conversion rank in both arguments, while the overload that you want to call requires a conversion from int
to double
which is not exact match.
The second argument is then considered the Compare
functor to be called for the comparison operation, but calling a double
fails obviously. The overload is not disabled if the second argument is not callable, which is why it is still chosen.
This doesn't happen with auto res = std::max(a, {b});
, because there is no overload with std::initializer_list
parameter for the second argument and so only the overload that you want to call is viable. The initializer list makes the second parameter a non-deduced context, which is why it works in contrast to auto res = std::max(a, b);
, which fails due to template argument deduction mismatch between the two arguments.
In your third 'experiment', you have an initializer list as the first argument to std::max
; thus, the compiler is attempting to use the following template (see cppreference):
template< class T, class Compare >
T max( std::initializer_list<T> ilist, Compare comp );
in which the second argument needs to be a comparison function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With