Reputation: 37706
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?
Upvotes: 4
Views: 346
Reputation: 30624
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 +
Upvotes: 6
Reputation: 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
Upvotes: -1
Reputation: 173044
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 !");
Upvotes: 1
Reputation: 563
Neither f1
or f2
are 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.
Upvotes: 3
Reputation: 8451
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.
Upvotes: 3