Причина, по которой это не удается, заключается в том, что когда вы указываете foo<Movable>
, функция, к которой вы привязываетесь:
void foo(Movable&&) // *must* be an rvalue
{
}
Однако значение, передаваемое std::bind
, будет не r-значением, а l-значением (хранится как член где-то в результирующем функторе bind
). То есть сгенерированный функтор сродни:
struct your_bind
{
your_bind(Movable arg0) :
arg0(arg0)
{}
void operator()()
{
foo<int>(arg0); // lvalue!
}
Movable arg0;
};
Построен как your_bind(Movable())
. Таким образом, вы можете увидеть, что это не удается, потому что Movable&&
не может связываться с Movable
. †
Вместо этого может быть простое решение:
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&&
, где T
- параметр шаблона, может быть выведен в что угодно , , если вы позволите ему быть .)