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
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke, std::forward(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. 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, we just want T&:
template
struct invoke_type
: std::add_lvalue_reference { };
template
struct invoke_type> {
using type = T&;
};
template
using invoke_type_t = typename invoke_type::type;
Plug that back into the original solution, and we get something that works for reference_wrapper too:
template
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke...>,
// ^^^^^^^^^^^^^^^^^^^
std::forward(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.