How can I best define the template function applyFunc to match lambda's the signature ?
As long as you accept to use non capturing lambdas only (as you did in the example code), you can exploit the fact that they decay to function pointers.
As a minimal, working example:
template<class E>
int applyFunc(int(*f)(E)) {
return f(E{});
}
int main() {
auto asLambda = [](int d) -> int { return d+d; };
applyFunc(+asLambda);
}
If you want to use capturing lambdas instead, you can extract the type E
somehow if you accept the followings:
- You must use a generic type
F
instead of a std::function
- You cannot use generic lambdas
Then, you can look directly at the operator()
of your lambda.
It follows a minimal, working example:
template<typename F>
struct GetFrom {
template<typename R, typename E>
static E typeE(R(F::*)(E) const);
// required for mutable lambdas
template<typename R, typename E>
static E typeE(R(F::*)(E));
};
template<class F>
int applyFunc(F f) {
using E = decltype(GetFrom<F>::typeE(&F::operator()));
return f(E{});
}
int main() {
int i = 0;
applyFunc([i](int d) mutable -> int { return d+d; });
applyFunc([i](int d) -> int { return d+d; });
}
You can easily extend it to multiple arguments if you need. Use a std::tuple
as a return type and get the i-th type from it.
Finally, if you want to use capturing lambdas and assign them to a std::function
for whatever reason, be aware that E
cannot be automatically deduced and thus you have to explicitly specify it (as suggested in the comments to the question by @cpplearner):
applyFunc<int>([](int d) { return d+d; })
EDIT
GetFrom
can also be used directly in SFINAE expressions, as requested in the comments.
As a minimal, working example:
#include<type_traits>
template<typename F>
struct GetFrom {
template<typename R, typename E>
static E typeE(R(F::*)(E) const);
// required for mutable lambdas
template<typename R, typename E>
static E typeE(R(F::*)(E));
};
template<class F, typename E = decltype(GetFrom<F>::typeE(&F::operator()))>
std::enable_if_t<std::is_same<E, int>::value, E>
applyFunc(F f) {
return f(E{});
}
template<class F, typename E = decltype(GetFrom<F>::typeE(&F::operator()))>
std::enable_if_t<std::is_same<E, double>::value, E>
applyFunc(F f) {
return f(E{});
}
int main() {
int i = 0;
applyFunc([i](int d) mutable -> int { return d+d; });
applyFunc([i](double d) -> int { return d+d; });
// this won't compile, as expected
// applyFunc([i](char d) -> int { return d+d; });
}