Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding function arguments in C++11

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?

Example

#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).

like image 358
Benjamin Kloster Avatar asked Mar 19 '13 13:03

Benjamin Kloster


People also ask

Why is it important to bind a function to its arguments?

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.

What does the bind function do in C?

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.

What is the use of std :: bind?

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.

What is boost :: bind?

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.


1 Answers

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.

like image 129
Xeo Avatar answered Sep 29 '22 05:09

Xeo