The following code does not compile:
#include
template
void invoke(Args&&... args)
{
}
template
Your understanding is correct - bind copies its arguments. So you have to provide the correct overload of invoke() that would be called on the lvalues:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args&...>, std::forward<Args>(args)...);
^^^^^^^^
binder();
}
This works on most types. There are a few exceptions enumerated in [func.bind.bind] for operator(), where Arg& is insufficient. One such, as you point out, is std::reference_wrapper<T>. We can get around that by replacing the Args&usage above with a type trait. Typically, we'd just add an lvalue reference, 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;
Plug that back into the original solution, and we get something that works for reference_wrapper too:
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<invoke_type_t<Args>...>,
// ^^^^^^^^^^^^^^^^^^^
std::forward<Args>(args)...);
binder();
}
Of course, if one of Arg is a placeholder this won't work anyway. And if it's a bind expression, you'll have to write something else too.