通过std :: bind传递rvalues

Tim*_*003 27 c++ std rvalue rvalue-reference c++11

我想将一个rvalue传递std::bind给一个在C++ 0x中采用rvalue引用的函数.我无法弄清楚该怎么做.例如:

#include <utility>
#include <functional>

template<class Type>
void foo(Type &&value)
{
    Type new_object = std::forward<Type>(value);    // move-construct if possible
}

class Movable
{
public:
    Movable(Movable &&) = default;
    Movable &operator=(Movable &&) = default;
};

int main()
{
    auto f = std::bind(foo<Movable>, Movable());
    f();    // error, but want the same effect as foo(Movable())
}
Run Code Online (Sandbox Code Playgroud)

GMa*_*ckG 30

失败的原因是因为当您指定时foo<Movable>,您绑定的函数是:

void foo(Movable&&) // *must* be an rvalue
{
}
Run Code Online (Sandbox Code Playgroud)

但是,传递的值std::bind不是右值,而是左值(在结果bind函子中的某个位置存储).那,生成的仿函数类似于:

struct your_bind
{
    your_bind(Movable arg0) :
    arg0(arg0)
    {}

    void operator()()
    {
        foo<int>(arg0); // lvalue!
    }

    Movable arg0;
};
Run Code Online (Sandbox Code Playgroud)

建造为your_bind(Movable()).所以你可以看到这个失败,因为Movable&&无法绑定Movable.†

一个简单的解决方案可能是这样:

auto f = std::bind(foo<Movable&>, Movable());
Run Code Online (Sandbox Code Playgroud)

因为现在你正在调用的函数是:

void foo(Movable& /* conceptually, this was Movable& &&
                        and collapsed to Movable& */)
{
}
Run Code Online (Sandbox Code Playgroud)

呼叫工作正常(当然,foo<const Movable&>如果需要,你可以做到这一点).但一个有趣的问题是,如果我们可以让你的原始绑定工作,我们可以通过:

auto f = std::bind(foo<Movable>,
            std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
                Movable()));
Run Code Online (Sandbox Code Playgroud)

也就是说,我们只是std::move在进行调用之前的参数,因此它可以绑定.但是,哎呀,这很难看.演员是必需的,因为std::move是一个重载函数,所以我们必须指定超载,我们希望通过强制转换为所需的类型,从而消除了其他选项.

如果std::move没有超载,它实际上不会那么糟糕,好像我们有类似的东西:

Movable&& my_special_move(Movable& x)
{
    return std::move(x);
}


auto f = std::bind(foo<Movable>, std::bind(my_special_move, Movable()));
Run Code Online (Sandbox Code Playgroud)

哪个更简单.但除非你有这样的功能,否则我认为很明显你可能只想指定一个更明确的模板参数.


†这与在没有显式模板参数的情况下调用函数不同,因为明确指定它会消除推导它的可能性.(T&&,T模板参数在哪里,可以推导出任何东西,如果你允许的话.)