Reputation: 465
I have a function which takes two std::function
s as arguments. The parameter of the second function has the same type as the result of the first.
I wrote a function template like this:
template<typename ResultType>
void examplFunction(std::function<ResultType()> func, std::function<void(ResultType)> func2) {
auto x = func();
func2(x);
}
I can call it with:
void f() {
examplFunction<int>([]() { return 1; }, //
[](int v) { std::cout << "result is " << v << std::endl; });
}
Is there a way to to get rid of the <int>
at examplFunction<int>
and let the compiler deduce the type of ResultType
?
Upvotes: 27
Views: 3240
Reputation: 329
Angew's answer is great (and should be the accepted answer), but is missing the minor detail of checking that the section function doesn't return anything. To do that you'll need to use the std::is_void
type trait, and std::enable_if:
template<class F1, class F2>
void examplFunction(F1 func, F2 func2, std::enable_if_t<std::is_void_v<decltype(func2(func()))>, void*> sfinae = nullptr) {
auto x = func();
func2(x);
}
This obvious is more verbose and difficult to read if you aren't familiar with type traits and SFINAE, so it probably isn't the best way forward if you don't need to make sure F2 returns void
.
Upvotes: 0
Reputation: 11940
std::function
has a templated (and otherwise unconstrained) constructor, so deducing it from simply an argument type is not that easy a deal. If those arguments still need to be std::function
s, you can skip one <int>
for the price of two std::function
s, and let deduction guides do the rest:
void f() {
examplFunction(std::function([]() { return 1; }), //
std::function([](int v) { std::cout << "result is "
<< v << std::endl; }));
}
A fun fact is that this does not always work. For instance, the current implementation of libc++ lacks guides for std::function
, thus violating the standard.
Upvotes: 3
Reputation: 23681
Yes, there is.
template<typename ResultType>
void examplFunction_impl(std::function<ResultType()> func, std::function<void(ResultType)> func2) {
auto x = func();
func2(x);
}
template<class F1, class F2>
void examplFunction(F1&& f1, F2&& f2)
{
using ResultType = decltype(f1());
examplFunction_impl<ResultType>(std::forward<F1>(f1), std::forward<F2>(f2));
}
In this case you require that f1
be invocable with no arguments, so you can figure out the return type in the helper function. Then you call the real function while explicitly specifying that return type.
You could add some SFINAE to make sure this function only participates in overload resolution when f1
can indeed be invoked like that (and if f2
can also be invoked with the return value of f1
).
Although I have to agree with @Angew that in the given example there is no need for std::function
. That might of course be different in a real-world situation.
Upvotes: 13
Reputation: 171117
Do you actually need std::function
in there? std::function
is useful when you need type erasure. With templates, you can usually skip it altogether:
template<class F1, class F2>
void examplFunction(F1 func, F2 func2, decltype(func2(func()))* sfinae = nullptr) {
auto x = func();
func2(x);
}
The sfinae
parameter makes sure the function can only be called with functions such that func2
can be called with the result of func
.
Upvotes: 27