Unexpected function deduction is happening in the following program. -
Case I -
template <typename T, typename>
void foo(T x, int) {
cout << "In int foo\n";
}
template <typename T>
void foo(T x, char) {
cout << "In char foo\n";
}
int main() {
string s = "Hello World";
foo(s, (int) 1);
}
Output
In char foo
Case II -
template <typename T>
void foo(T x, int) {
cout << "In int foo\n";
}
template <typename T>
void foo(T x, char) {
cout << "In char foo\n";
}
int main() {
string s = "Hello World";
foo(s, (int) 1);
}
Output
In int foo
For case II, I just removed the last template parameter typename from the first function. Could someone please explain what's happening here?
In this function,
template <typename T, typename>
void foo(T x, int) {
cout << "In int foo\n";
}
You tell the compiler that,
T
and the other is int
. When compiling foo(s, (int) 1);
, the compiler knows the type of T
as its given by the argument, the second argument is also given. But the second template argument is unknown. So the compiler tries to find the other most suitable one, which in this case the other foo
function.
This time the compiler tests it out once again and it passes, as int
can be implicitly converted to char
. This is why it outputs In char foo
in the first case.
In the second case, since there are no unknown types, the most suitable one is the first function void foo(T x, int)
. That's because the second argument type is int
and the function's second parameter types is also int
.
To resolve the issue in the first case, you can provide a default type argument to the template. This way it knows the second type parameter, thus will work without an issue.
template <typename T, typename = void>
void foo(T x, int) {
cout << "In int foo\n";
}
It's a bit equivalent to this and be surprised by the result:
void foo(int a, int);
void foo(float b);
int main () {
foo((int) 1); // calls the float version
}
Why does it calls the float version? Because you're missing the second int parameter! You simply just cannot call that version if you only send one parameter
Simply removing the second int
parameter make it callable!
Same with with your code. Your function foo
takes two template parameter, only one can be deduced, and you're not sending them to the compiler. Removing one will make it work. You could also set a default value:
template <typename T, typename = void>
void foo(T x, int) {
cout << "In int foo\n";
}
The compiler will be able to select this one, since it has a default value for the second template parameter you're not providing.
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.