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?
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 +
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With