I'd like to generically "pickle" function calls so they can be executed later. The return type of those functions will always be void
(for now). Something like this:
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(F, args...);
}
The problem is, if args
contains a const reference, std::bind
tries to copy construct the value, which is not always desired or even valid if the type lacks a copy constructor. How do I forward the arguments in a way that uses std::ref
for lvalue references and the normal std::forward
for lvalue references?
#include <functional>
class NonCopyable {
public:
NonCopyable() {}
NonCopyable(const NonCopyable&) = delete;
};
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args)
{
return std::bind(function, std::forward<Args>(args)...);
}
int main()
{
NonCopyable obj;
auto f = pickle(
[](const NonCopyable&) {},
obj
);
return 0;
}
The above snippet won't compile, complaining about the deleted copy constructor. (I used forward here because someone suggested it, but has since deleted their answer, it seems).
Bind function with the help of placeholders helps to manipulate the position and number of values to be used by the function and modifies the function according to the desired output.
The bind() function binds a unique local name to the socket with descriptor socket. After calling socket(), a descriptor does not have a name associated with it. However, it does belong to a particular address family as specified when socket() is called. The exact format of a name depends on the address family.
std::bind is a Standard Function Objects that acts as a Functional Adaptor i.e. it takes a function as input and returns a new function Object as an output with with one or more of the arguments of passed function bound or rearranged.
boost::bind is a generalization of the standard functions std::bind1st and std::bind2nd. It supports arbitrary function objects, functions, function pointers, and member function pointers, and is able to bind any argument to a specific value or route input arguments into arbitrary positions.
Overloading, yay.
// also does the correct thing for `T const`
template<class T>
std::reference_wrapper<T> maybe_ref(T& v, int){ return std::ref(v); }
// just forward rvalues along
template<class T>
T&& maybe_ref(T&& v, long){ return std::forward<T>(v); }
template<typename F, typename... Args>
std::function<void()>
pickle(F function, Args&&... args) {
return std::bind(function, maybe_ref(std::forward<Args>(args), 0)...);
}
The int
/long
parameters and 0
argument disambiguate the lvalue case for compilers that find the overloads to be ambiguous, and doesn't do any harm otherwise.
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