std::bind and perfect forwarding

后端 未结 1 1632
温柔的废话
温柔的废话 2021-01-06 02:54

The following code does not compile:

#include 

template
void invoke(Args&&... args)
{
}

template

        
1条回答
  •  予麋鹿
    予麋鹿 (楼主)
    2021-01-06 03:15

    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.

    0 讨论(0)
提交回复
热议问题