简体   繁体   中英

Wrong template function deduction

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,

  1. There are 2 template parameters.
  2. The return is void.
  3. Takes two parameters, one from type T and the other is int .
  4. Then the function body.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM