失败的原因是,当您指定 时foo<Movable>
,您要绑定的函数是:
void foo(Movable&&) // *must* be an rvalue
{
}
但是,传递的值std::bind
不会是右值,而是左值(作为成员存储在结果bind
函子的某处)。也就是说,生成的仿函数类似于:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo<int>(arg0); // lvalue!
}
Movable arg0;
};
构造为your_bind(Movable())
。所以你可以看到这失败了,因为Movable&&
无法绑定到Movable
.†</p>
一个简单的解决方案可能是这样的:
auto f = std::bind(foo<Movable&>, Movable());
因为现在你调用的函数是:
void foo(Movable& /* conceptually, this was Movable& &&
and collapsed to Movable& */)
{
}
而且通话效果很好(当然,foo<const Movable&>
如果需要,您可以这样做)。但一个有趣的问题是,我们是否可以让您原来的绑定工作,我们可以通过:
auto f = std::bind(foo<Movable>,
std::bind(static_cast<Movable&&(&)(Movable&)>(std::move<Movable&>),
Movable()));
也就是说,我们只是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()));
这要简单得多。但是除非你有这样的函数,否则我认为很明显你可能只想指定一个更明确的模板参数。
† 这与在没有显式模板参数的情况下调用函数不同,因为显式指定它会消除推断它的可能性。( T&&
, whereT
是一个模板参数,可以推导出任何东西,如果你允许的话。)