How compiler to decide which function to call when overloading two function templates:
#include <iostream>
#include <typeinfo>
#ifndef B1
template <typename T1, typename T2>
auto max(T1 a, T2 b) {
std::cout << "auto version called" << std::endl;
return b < a ? a : b;
}
#endif
#ifndef B2
template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b) {
std::cout << "RT version called" << std::endl;
return b < a ? a : b;
}
#endif
template <typename T>
void print(T t) {
std::cout << typeid(t).name() << std::endl;
}
int main() {
auto b = ::max<long double>(4, 7.2);
print(b);
auto c = ::max<int>(4, 7.2);
print(c);
auto d = ::max<double>(4, 7.2);
print(d);
return 0;
}
I built the code with command:
$ g++ -o m1 ./maxdefault4.cpp -std=c++14 -DB1
$ g++ -o m2 ./maxdefault4.cpp -std=c++14 -DB2
It means that both two function template can match, but why no ambiguity error caused. And if buid with command:
$ g++ -o m ./maxdefault4.cpp -std=c++14
the compiler show me the error:
error: call to 'max' is ambiguous
auto c = ::max<int>(4, 7.2);
I built the code with command:
$ g++ -o m1 ./maxdefault4.cpp -std=c++14 -DB1
$ g++ -o m2 ./maxdefault4.cpp -std=c++14 -DB2It means that both two function template can match, but why no ambiguity error caused.
That's not correct: when you pass -DB1, or -DB2, you are compiling only one template, so there is no question of any ambiguity, and it's not surprising that it compiles.
And if buid with command:
$ g++ -o m ./maxdefault4.cpp -std=c++14the compiler show me the error: ...
That happens when you compile both the templates, and is much more interesting since some calls compile, but others don't.
To understand what's happening, let's see what happens when you have the following templates:
template <typename T1, typename T2>
auto max(T1 a, T2 b); // #1
template <typename RT, typename T1, typename T2>
RT max(T1 a, T2 b); // #2
and you make the call:
max<double>(4, 7.2);
Here, the compiler will substitute the provided parameter double, and deduce the remaining template parameters from the arguments.
This results in the generation of:
template<>
double max<double, double>(double a, double b); // #1' from #1
// T1 = double (explicitly specified for 1st template parameter)
// T2 = double (deduced from 2nd function argument)
template<>
double max<double, int, double>(int a, double b); // #2' from #2
// RT = double (explicitly specified for 1st template parameter)
// T1 = int (deduced from 1st function argument)
// T2 = double (deduced from 2nd function argument)
Now overload resolution is used to figure out that #2' is a better match for the arguments 4, and 7.2, so #2' is called.
Similarly, for this call:
max<int>(4, 7.2);
the compiler will substitute the provided parameter int, and deduce the remaining template parameters from the arguments.
This results in the generation of:
template<>
double max<int, double>(int a, double b); // #1' from #1
// T1 = int (explicitly specified for 1st template parameter)
// T2 = double (deduced from 2nd function argument)
template<>
int max<int, int, double>(int a, double b); // #2' from #2
// RT = int (explicitly specified for 1st template parameter)
// T1 = int (deduced from 1st function argument)
// T2 = double (deduced from 2nd function argument)
Now overload resolution is used, but there is an ambiguity between #1', and #2', since neither is a better match than the other (note that the return type plays no part in overload resolution). This causes the error that you observed.
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