Ответ 1

std::move принимает объект и позволяет рассматривать его как временное (значение rvalue). Хотя это не семантическое требование, обычно функция, принимающая ссылку на rvalue, лишает ее права. Когда вы видите std::move, это означает, что значение объекта не должно использоваться впоследствии, но вы все равно можете присвоить новое значение и продолжить его использование.

std::forward имеет один прецедент: применить шаблонный функциональный параметр (внутри функции) к категории значений (lvalue или rvalue), вызывающий, используемый для его передачи. Это позволяет передавать аргументы rvalue как rvalues ​​и lvalues, которые должны передаваться как lvalues, схема, называемая "совершенная пересылка".

В проиллюстрировать:

void overloaded( int const &arg ) { std::cout << "by lvalue\n"; }
void overloaded( int && arg ) { std::cout << "by rvalue\n"; }

template< typename t >
/* "t &&" with "t" being template param is special, and  adjusts "t" to be
   (for example) "int &" or non-ref "int" so std::forward knows what to do. */
void forwarding( t && arg ) {
    std::cout << "via std::forward: ";
    overloaded( std::forward< t >( arg ) );
    std::cout << "via std::move: ";
    overloaded( std::move( arg ) ); // conceptually this would invalidate arg
    std::cout << "by simple passing: ";
    overloaded( arg );
}

int main() {
    std::cout << "initial caller passes rvalue:\n";
    forwarding( 5 );
    std::cout << "initial caller passes lvalue:\n";
    int x = 5;
    forwarding( x );
}

Как упоминает Говард, есть также сходства, так как обе эти функции просто передаются в ссылочный тип. Но вне этих конкретных случаев использования (которые покрывают 99,9% полезности ссылок на ссылки rvalue), вы должны использовать static_cast напрямую и написать хорошее объяснение того, что вы делаете.

Ответ 2

Оба std::forward и std::move - не что иное, как отбрасывание.

X x;
std::move(x);

Вышеприведенное выражение lvalue x типа X относится к выражению rvalue типа X (точное значение x). move также может принимать значение r:

std::move(make_X());

и в этом случае это тождественная функция: принимает r-значение типа X и возвращает r-значение типа X.

С помощью std::forward вы можете в какой-то степени выбрать пункт назначения:

X x;
std::forward<Y>(x);

Выдает выражение l x типа X выражению типа Y. Существуют ограничения на то, что Y может быть.

Y может быть доступной базой X или ссылкой на базу X. Y может быть X или ссылкой на X. Нельзя отбрасывать cv-квалификаторы с forward, но можно добавить cv -qualifiers. Y не может быть типом, который просто конвертируется из X, за исключением использования доступного преобразования Base.

Если Y является ссылкой на lvalue, результатом будет выражение lvalue. Если Y не является ссылкой lvalue, результатом будет выражение rvalue (значение xvalue to exact).

forward может принимать аргумент rvalue только в том случае, если Y не является ссылкой lvalue. То есть вы не можете присвоить значение rvalue для lvalue. Это по соображениям безопасности, так как это обычно приводит к оборванным ссылкам. Но приведение rvalue к rvalue в норме и разрешено.

Если вы попытаетесь указать Y на то, что не разрешено, ошибка будет обнаружена во время компиляции, а не время выполнения.

Ответ 3

std::forward используется для пересылки параметра точно так, как он передавался функции. Как показано здесь:

Когда использовать std:: forward для пересылки аргументов?

Использование std::move предлагает объект как rvalue, возможно, соответствующий конструктору перемещения или функции, принимающей значения r. Он делает это для std::move(x), даже если x не является rvalue сам по себе.