std :: bind和完美的转发 [英] std::bind and perfect forwarding
问题描述
以下代码无法编译:
#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);
}
如果我理解正确,原因如下:std::bind
复制其参数,并在调用binder
的operator()
时,将所有绑定的参数作为 lvalues 传递. -甚至那些以 rvalues 形式输入bind
的代码.但是invoke
是为原始参数实例化的,它不能接受binder
试图传递它的内容.
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?
推荐答案
您的理解是正确的-bind
复制其参数.因此,您必须提供将在左值上调用的invoke()
的正确重载:
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();
}
这适用于大多数类型. [func.bind.bind]中为 operator()
,其中Arg&
不足.如您所指出的,其中之一是std::reference_wrapper<T>
.我们可以通过将上面的Args&
用法替换为类型trait来解决此问题.通常,我们只添加一个左值引用,但对于reference_wrapper<T>
,我们只需要T&
:
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;
将其插入原始解决方案中,我们也会得到适用于reference_wrapper
的内容:
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();
}
当然,如果Arg
中的一个是占位符,则无论如何都不会起作用.而且,如果这是一个绑定表达式,那么您还必须编写其他内容.
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.
这篇关于std :: bind和完美的转发的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!