【问题标题】:std::bind and perfect forwardingstd::bind 和完美转发
【发布时间】:2015-09-07 05:35:30
【问题描述】:

以下代码无法编译:

#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() 时,它会将所有绑定的参数作为左值传递- 即使是那些输入bind 作为rvalues 的。但是 invoke 是为原始参数实例化的,它不能接受 binder 试图传递的内容。

这个问题有解决办法吗?

【问题讨论】:

    标签: c++ c++11 perfect-forwarding stdbind


    【解决方案1】:

    您的理解是正确的 - bind 复制了它的论点。因此,您必须提供正确的 invoke() 重载,以便在左值上调用:

    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&amp; 是不够的。正如您所指出的,其中之一是std::reference_wrapper&lt;T&gt;。我们可以通过用类型特征替换上面的Args&amp;usage 来解决这个问题。通常,我们只需要添加一个左值引用,但对于reference_wrapper&lt;T&gt;,我们只需要T&amp;:

    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:

    template<class ...Args>
    void bind_and_forward(Args&&... args)
    {
        auto binder = std::bind(&invoke<invoke_type_t<Args>...>, 
                                //      ^^^^^^^^^^^^^^^^^^^
                                std::forward<Args>(args)...);
        binder();
    }
    

    当然,如果Arg 之一是占位符,这无论如何都不起作用。如果它是一个绑定表达式,你也必须写一些别的东西。

    【讨论】:

    • 但在这种情况下,它不会为使用 std::ref() 包装的参数编译。
    • @IgorR。为那个更新了 - bind() 为 std::ref() 做了一些特别的事情。所以你也必须做一些特别的事情。
    猜你喜欢
    • 2015-04-11
    • 1970-01-01
    • 2013-08-25
    • 2012-06-23
    • 2014-01-04
    • 1970-01-01
    • 1970-01-01
    • 2021-12-17
    • 1970-01-01
    相关资源
    最近更新 更多