4

According to the first answer to this question: function template overloading, a "A non-templated (or "less templated") overload is preferred to templates".

#include <iostream>
#include <string>
#include <functional>

void f1(std::string const& str) {
    std::cout << "f1 " << str << "\n";
}

template <typename Callback, typename... InputArgs>
void call(Callback callback, InputArgs ...args) {
    callback(args...);
}

void call(std::function<void(std::string const&)> callback, const char *str) {
    std::cout << "custom call: ";
    callback(str);
}

int main() {
    auto f2 = [](std::string const& str) -> void {
        std::cout << "f2 " << str << "\n";
    };

    call(f1, "Hello World!");
    call(f2, "Salut Monde !");

    return 0;
}

Where, as far as I understand it, the second definition of call is "non-templated", and thus should be chosen over the first one when I do call(f1, "1") or call(f2, "2").

This is not the case, I get the following output:

f1 Hello World!
f2 Salut Monde !

If I remove the templated version of call, I get the expected output.

Why is my overload of call not chosen over the first one in this case?

Holt
  • 36,600
  • 7
  • 92
  • 139
  • The non-template is only preferred when the parameter type is an exact match. In the thread you linked to, note the example where `10` matches the non-template but `10u` matches the template. – M.M Mar 08 '16 at 09:16

5 Answers5

6

The types for f1 and f2 are not std::function, a user defined conversion is needed, thus the template version is chosen instead.

If you did provide a function call that is an exact match for a function pointer, such as;

void call (void(*callback)(std::string const&), const char *str)

It would be chosen for f1.


Note: with the addition of the unary + on the lambda, you can also get a function pointer in this case (your capture list is empty)...

auto f2 = +[](std::string const& str) -> void
//        ^ unary +
Niall
  • 30,036
  • 10
  • 99
  • 142
  • 1
    One of the classic articles on overloaded and specialised template functions is this from Herb Sutter; http://www.gotw.ca/publications/mill17.htm – Niall Mar 08 '16 at 09:29
3

The type of the lambda f2 is not std::function<void(std::string const&)>, it is a compiler generated type. Therefore the templated call provided a better match.

Community
  • 1
  • 1
Daniel
  • 8,179
  • 6
  • 31
  • 56
3

Neither f1 or f2are of type std::function<...>. Therefore the template is a better match.

If you use (as example)

std::function<void(std::string const&)> f3(f2);
call(f3, "Salut Monde !");

your call is used.

MagunRa
  • 543
  • 4
  • 13
1

std::function could be constructed from function or lambda expressions, but its type is not same as function or lambda expressions. The arguments don't match perfectly for:

call(f1, "Hello World!");
call(f2, "Salut Monde !");

You can use casting to accomplish it:

call(static_cast<std::function<void(std::string const&)>>(f1), "Hello World!");
call(static_cast<std::function<void(std::string const&)>>(f2), "Salut Monde !");

LIVE

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
-1

when you overload the function with specific type(function's second argument) in this case when you call the function with specific argument then template function will not call because you already write the function for specific type. except the specific type your template function call , it is compiler jobs to select specific type argument first and then template function

S Prakash
  • 1
  • 3