User-defined overloaded max function call giving error: "call of overloaded 'max<int>(int, int)' is ambiguous"

95 Views Asked by At

User-defined overloaded max function call gives error:

call of overloaded 'max(int, int)' is ambiguous

#include <iostream>

template <typename T1, typename T2>
auto max(T1 a, T2 b)
{
    return b<a?a:b;
}

template<typename RT, typename T1, typename T2>
RT max(T1 a, T2 b)
{
    return b<a?a:b;
}

int main() 
{
    auto rt = ::max(4,7);
    std::cout<<typeid(rt).name()<<std::endl;
    auto rrt = ::max<int>(4,7);
    std::cout<<typeid(rrt).name()<<std::endl;
    return 0;
}

Output:

/tmp/X2ZgbGkKk9.cpp: In function 'int main()':
/tmp/X2ZgbGkKk9.cpp:21:26: error: call of overloaded 'max<int>(int, int)' is ambiguous
   21 |     auto rrt = ::max<int>(4,7);
      |                ~~~~~~~~~~^~~~~
/tmp/X2ZgbGkKk9.cpp:5:6: note: candidate: 'auto max(T1, T2) [with T1 = int; T2 = int]'
    5 | auto max(T1 a, T2 b)
      |      ^~~
/tmp/X2ZgbGkKk9.cpp:11:4: note: candidate: 'RT max(T1, T2) [with RT = int; T1 = int; T2 = int]'
   11 | RT max(T1 a, T2 b)

If the template argument is set to int in the following line, the ambiguous error is thrown:

auto rrt = ::max<int>(4,7);

Whereas it works if the template argument is changed to double, i.e.:

auto rrt = ::max<double>(4,7);

I failed to understand the reason. Please help.

1

There are 1 best solutions below

1
Weijun Zhou On

When you don't provide template parameters, only the first overload is available because in the second overload the type RT is not deducible, so there is no ambiguity, and the call to ::max(4,7) succeeds, calling the first overload, with both T1 and T2 deduced to int.

When you provide one template parameter, both overloads become available. The call ::max<int>(4,7) can either call the first overload with T1 explicitly set to int and T2 deduced to be int, or call the second overload with RT explicitly set to int and both T1 and T2 deduced to be int. After substituting the types, the signatures of both overloads are auto(int,int) and int(int,int). They are equally good in overload resolution and therefore ambiguity occurs.

When you do ::max<double>(4,7), again both overloads are available. Following the same logic, the signature of the two overloads would be auto(double,int) and double(int,int). In this case, the first overload requires an additional conversion in the argument, and hence less favorable, and the second overload is unambiguously picked, hence no ambiguity arises.

You can read more about overload resolution here.