Здесь `std:: move` необходимо?

Требуется ли std::move в следующем фрагменте?

std::function<void(int)> my_std_function;

void call(std::function<void(int)>&& other_function)
{
  my_std_function.swap(std::move(other_function));
}

Насколько я знаю, call() принимает ссылку на rvalue.. но так как ссылка rvalue сама является lvalue, для вызова swap(std::function<void(int)>&&) мне нужно переставить это значение в ссылку rvalue с помощью std::move

Могут ли мои рассуждения правильные или std::move в этом случае могут быть опущены (и если это возможно, почему?)

Ответы

Ответ 1

std::function::swap не принимает свой параметр по ссылке rvalue. Это просто регулярная ссылка const lvalue. Таким образом, std::move бесполезен (и, вероятно, не должен компилироваться, поскольку ссылки rvalue не могут связываться с ссылками lvalue).

other_function также не обязательно должен быть ссылкой rvalue.

Ответ 2

Подпись

void std::function<Sig>::swap( function& other )

поэтому код не должен компилироваться с помощью std::move (у msvc есть расширение, чтобы разрешить эту привязку:/)

Когда вы берете ссылку на r-значение, я думаю, что простое назначение - это то, что вы хотите в своем случае:

std::function<void(int)> my_std_function;

void call(std::function<void(int)>&& other_function)
{
  my_std_function = std::move(other_function); // Move here to avoid copy
}

Ответ 3

В этом случае это не имеет значения, поскольку std::function::swap принимает ссылку на константу lvalue. Он даже не должен компилироваться с помощью std::move.

Если вы использовали функцию, которая разрешала rvalues, тогда вам нужно было бы вызвать std::move, поскольку other_function является значением lvalue, хотя тип его является ссылкой rvalue. Например:

struct Foo {
    Foo()=default;
    Foo(const Foo&) { std::cout << "copy" << std::endl; }
    Foo(Foo&&) { std::cout << "move" << std::endl; }
};

void bar (Foo&& a) {
    Foo b {a};            //copy
    Foo c {std::move(a)}; //move
}

Ответ 4

Вы правы в определенном смысле; чтобы снова получить rvalue, вам понадобится std::move.

Однако для вызова swap не требуется rvalue или rvalue reference — просто равная ссылка.

Итак, вы можете пойти без кавычек std::move.

В терминах семантики перемещения операция свопинга довольно низкоуровневая. Вы обнаружите, что большинство полезных шагов в конечном итоге реализованы рядом свопов, поэтому имеет смысл, что сами свопы не используют семантику перемещения. Действительно, как они?