Оба std::forward
и std::move
ничто иное как слепки.
X x;
std::move(x);
Выше приведено выражение lvalue x
типа X к выражению rvalue типа X (точнее, xvalue). move
также можно принять значение:
std::move(make_X());
и в этом случае это функция тождества: принимает r-значение типа X и возвращает r-значение типа X.
С помощью std::forward
вы можете выбрать пункт назначения в некоторой степени:
X x;
std::forward<Y>(x);
Приводит выражение lvalue x
типа X к выражению типа Y. Существуют ограничения на то, что может быть Y.
Y может быть доступной Базой X, или ссылкой на Базу X. Y может быть X, или ссылкой на X. Нельзя отбрасывать cv-квалификаторы с помощью forward
, но можно добавлять cv-квалификаторы. Y не может быть типом, который просто конвертируется из X, кроме как через доступное базовое преобразование.
Если Y является ссылкой lvalue, результатом будет выражение lvalue. Если Y не является ссылкой lvalue, результатом будет выражение rvalue (точнее xvalue).
forward
может принимать аргумент rvalue, только если Y не является ссылкой lvalue. То есть вы не можете привести значение к значению lvalue. Это по соображениям безопасности, так как это обычно приводит к висящим ссылкам. Но приведение rvalue к rvalue - это нормально и разрешено.
Если вы попытаетесь указать Y для чего-то, что не разрешено, ошибка будет обнаружена во время компиляции, а не во время выполнения.