Reputation: 247
The concept of callable is defined in http://en.cppreference.com/w/cpp/concept/Callable.
Suppose I have a callable object f that has one argument of type T* and return type void. f can be any callable type (a function object, a pointer to member function, a pointer to data member, etc). How can I invoke f?
Simply calling f(x) fails since f can be a pointer to member function or data member. Is there a simple way to call f? One possible solution is std::bind(f, x)(), but this solution becomes more complex when f has more arguments.
Upvotes: 11
Views: 5859
Reputation: 25367
Rather than implementing INVOKE
yourself, use one of the library features that uses it. In particular, std::reference_wrapper
works. Thus you can have the effect of std::invoke(f, args...)
with std::ref(f)(args...)
:
template<typename F, typename... Args>
auto invoke(F f, Args&&... args)
-> decltype(std::ref(f)(std::forward<Args>(args)...))
{
return std::ref(f)(std::forward<Args>(args)...);
}
I didn't forward f
because std::reference_wrapper
requires that the object passed in is not an rvalue. Using std::bind
instead of std::ref
doesn't fix the problem. What this means is that for a function object like this:
struct F
{
void operator()() && {
std::cout << "Rvalue\n";
}
void operator()() const& {
std::cout << "Lvalue\n";
}
};
invoke(F{})
will print Lvalue
, whereas std::invoke(F{})
in C++17 would print Rvalue
.
I found the technique from this paper
Upvotes: 10
Reputation: 25367
Use boost::hof::apply
:
#include <boost/hof/apply.hpp>
// ...
boost::hof::apply(f, args...);
boost::hof::apply
performs the same operation that INVOKE
does.
Alternatively, use boost::hana::apply
, which does the same thing
Upvotes: 0
Reputation: 64308
This is exactly what std::invoke
does, but it won't be standard until C++17. You can make your own version, but it can be pretty complicated if it is fully general.
Here's the basic idea for two cases (code taken from cppreference.com):
template <class F, class... Args>
inline auto INVOKE(F&& f, Args&&... args) ->
decltype(std::forward<F>(f)(std::forward<Args>(args)...)) {
return std::forward<F>(f)(std::forward<Args>(args)...);
}
template <class Base, class T, class Derived>
inline auto INVOKE(T Base::*pmd, Derived&& ref) ->
decltype(std::forward<Derived>(ref).*pmd) {
return std::forward<Derived>(ref).*pmd;
}
Upvotes: 9