Function templates - a function to select a compiler with different types of parameters when calling the same type

I was playing around with function templates and I came across strange interactions.

template<class T1, class T2>
void foo(T1, T1);

template<class T1, class T2>
void foo(T1, T2);

//main
foo(1,1)

      

This calls foo (T1, T2) and I don't understand why. How will it work? Are these functions overloads of each other and why does the compiler pick one with different types of parameters?

this particular interaction was explained in the first part of Henri Menke's post


After some more confusion, I found something weirder

#include <iostream>

template<class T1, class T2>
void foo(T1 a, T1 b)
{
    std::cout << "same\n";
}

template<class T1, class T2>
void foo(T1 a, T2 b)
{
    std::cout << "different\n";
}

int main()
{
    foo(1, 1);
    foo<int, int>(1, 1);
}

      

In this code, I am getting the result

different
different

      

but after commenting the 1st call like

int main()
{
    //foo(1, 1);
    foo<int, int>(1, 1);
}

      

result

same

      

I am using VS2015 and if I write the same in Ideone ( like here ) the result for the first is

different
same

      

Can anyone explain what is happening (or not)?


By the way, I came to the conclusion that the call foo<int, int>(1, 1);

should be ambiguous. Both function templates have the same signature then and come from the same template. So it's another matter, why don't they collide?

+3


source to share


1 answer


It's easy to see why this fails by simply removing the second pattern, i.e. having a source file like

template<class T1, class T2>
void foo(T1, T1);

int main()
{
  foo(1,1);
}

      

This does not work in Clang with error

test.cpp:6:3: error: no matching function for call to 'foo'
  foo(1,1);
  ^~~
test.cpp:2:6: note: candidate template ignored: couldn't infer template argument
      'T2'
void foo(T1, T1);
     ^
1 error generated.

      

The compiler has no way of inferring the second template parameter T2

.


If you remove the extra T2

from the first template and use this type of source file

template<class T1>
void foo(T1, T1);

template<class T1, class T2>
void foo(T1, T2);

int main()
{
  foo(1,1);
}

      

The compiler will always choose the first option (if T1

they T2

match, of course) because it is more specialized.



Another option is to give T2

a default value. Then the first variant can also be created from foo(1,1)

.

template<class T1, class T2 = void>
void foo(T1, T1);

      


Another interesting thing:

#include <iostream>

template<class T1, class T2>
void foo(T1, T1)
{ std::cout << "First choice!\n"; }

template<class T1, class T2>
void foo(T1, T2)
{ std::cout << "Second choice!\n"; }

int main()
{
  foo<int,int>(1,1);
}

      

This will be output at runtime:

First choice!

      

I'm not entirely sure, but I believe this is due to the fact that in the case of deduction (although it is not done here), for the first option, the compiler would only have to infer one type instead of two, making it a more specialized option.

+4


source







All Articles