问题
The following code does not compile:
#include <functional>
template<class ...Args>
void invoke(Args&&... args)
{
}
template<class ...Args>
void bind_and_forward(Args&&... args)
{
auto binder = std::bind(&invoke<Args...>, std::forward<Args>(args)...);
binder();
}
int main()
{
int a = 1;
bind_and_forward(a, 2);
}
If I understand correctly, the reason is as follows: std::bind
copies its arguments, and when the binder
's operator()
is called, it passes all the bound arguments as lvalues - even those ones that entered bind
as rvalues. But invoke
was instantiated for the original arguments, and it can't accept what the binder
attempts to pass it.
Is there any solution for this problem?
回答1:
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.
来源:https://stackoverflow.com/questions/30968573/stdbind-and-perfect-forwarding