Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How compiler decide which function template to call?

Tags:

c++

templates

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);
like image 931
Ryan Avatar asked Sep 09 '26 06:09

Ryan


1 Answers

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.

like image 55
cigien Avatar answered Sep 11 '26 19:09

cigien