I was playing around with function templates and I stumbled across a weird interaction.
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 would that work? Are these functions overloads of each other, and why would the compiler choose the one with different parameter types?
this particular interaction was explained in the first part of Henri Menke's post
After some more messing around 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 get a result
different
different
but after commenting out the 1st call like
int main()
{
//foo(1, 1);
foo<int, int>(1, 1);
}
the result is
same
I'm using VS2015 and if I write the same thing in Ideone ( like here ) the result for the 1st one is
different
same
Could somebody be able to explain what is (or isn't) going on?
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 that is another thing, why don't they collide?
It is easy to see why this fails by simply deleting the second template, ie having a source file like
template<class T1, class T2>
void foo(T1, T1);
int main()
{
foo(1,1);
}
This fails in Clang with the 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 to deduce the second template parameter T2
.
If you delete the superfluous T2
from the first template and use this kind 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 the first option (if T1
and T2
are the same of course) because it is more specialised.
Another option is to give T2
a default value. Then the first variant can also be instantiated from foo(1,1)
.
template<class T1, class T2 = void>
void foo(T1, T1);
Another interesting thing is this:
#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 output at runtime:
First choice!
I'm not entirely sure, but I believe this is because in the case of deduction (even though it is not carried out here), for the first variant the compiler would have to deduce only one type instead of two which makes it the more specialised option.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.