Your understanding is correct - bind copies its arguments. Thus, you must ensure that invoke() properly overloaded, which will be called on lvalues:
template<class ...Args> void bind_and_forward(Args&&... args) { auto binder = std::bind(&invoke<Args&...>, std::forward<Args>(args)...); ^^^^^^^^ binder(); }
This works for most types. There are a few exceptions listed in [func.bind.bind] for operator() , where Arg& not enough. One of the ones you specify is std::reference_wrapper<T> . We can get around this by replacing the use of Args& above with a type of type. Typically, we just add an lvalue link, but for reference_wrapper<T> we just want T& :
template <typename Arg> struct invoke_type : std::add_lvalue_reference<Arg> { }; template <typename T> struct invoke_type<std::reference_wrapper<T>> { using type = T&; }; template <typename T> using invoke_type_t = typename invoke_type<T>::type;
Paste this back into the original solution, and we get something that works for reference_wrapper :
template<class ...Args> void bind_and_forward(Args&&... args) { auto binder = std::bind(&invoke<invoke_type_t<Args>...>,
Of course, if one of Arg is a placeholder, it still won't work. And if it's a binding expression, you will also have to write something else.
Barry source share