std :: bind和完美的转发 [英] std::bind and perfect forwarding

查看:165
本文介绍了std :: bind和完美的转发的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下代码无法编译:

#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复制其参数,并在调用binderoperator()时,将所有绑定的参数作为 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆