I'm attempting to make a template function that takes a function as a parameter and the parameter function has arguments for the template to deduce.
Example time:
Here is a function that accepts a fixed function type and works
void func_a(void(*func)(int)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_a(f);
return 0;
}
Here is what I want to do, expanding on the first example (this won't compile)
template <typename... T>
void func_b(void(*func)(T...)) {
func(1);
}
int main() {
auto f = [](int x) -> void { printf("%i\n", x); };
func_b(f); // neither of
func_b<int>(f); // these work
return 0;
}
Ideally I'd like func_b
to accept both a regular function and a lambda function like func_a
does, but with template magics.
Unfortunately, template deduction doesn't work well with implicit conversions. However, you can convert the lambda explicitly into a function pointer type. The shortest, but somewhat confusing way to do that is to apply unary + operator:
func_b(+f);
Or you could use the more intuitive, but also verbose and DRY-violating cast operation:
func_b(static_cast<void(*)(int)>(f));
But perhaps, you'll want to simply accept any callable type, instead of only function pointers:
template <class Fun>
void func_c(Fun&& func) {
func(1);
}
This works fine with lambdas. No conversions involved.
func_c(f);
And it also works for capturing lambdas (that cannot be converted to function pointers), std::function
and function objects such as those defined in <functional>
.
here you have some options that work:
#include <functional>
template <typename T>
void func_b(T&& func) {
func(1);
}
template <typename... T>
void func_c(std::function<void(T...)> func) {
func(1);
}
template <typename... T>
void func_d1(std::function<void(T...)> func) {
func(1);
}
template<typename... Params>
using fun = std::function<void(Params...)>;
template <typename T, typename... P>
void func_d(T& func) {
func_d1(fun<P...>(func));
}
int main() {
auto f = [](int x) { printf("%i\n", x); };
func_b(f);
func_b(std::function<void(int)>(f));
func_c(std::function<void(int)>(f));
func_d<decltype(f),int>(f);
return 0;
}
The issue is: A lambda is not a function pointer or std::function
-object.
func_b
uses perfect forwarding so T
will be the type of the lambda not a std::function
object.
For func_c
. You should not convert a lambda to a c-style function pointer. A std::function
object is able to do this conversion but only explicitly (by design) so you need to explicitly convert them.
func_d
(and func_d1
) combine the other aspects. It forwards the lambda and makes a std::function
-object explicitly out of it though it needs an additional template parameter.
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