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.
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++14
the 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.