Нужно ли сочетать std::move с std::forward при использовании ссылок переадресации?

Нужно ли объединять std::move с std::forward при использовании универсальных ссылок? Например, какой из следующих двух фрагментов кода правильный?

void bar(auto && x) {
    auto y(std::move(std::forward<decltype(x)>(x)));
}

or

void bar(auto && x) {
    auto y(std::move(x));
}

По сути, я хочу переместить память x в y, и мне все равно, является ли это ссылкой на l-значение или ссылкой на r-значение. Конечно, мне не нужны здесь значения const.


person wyer33    schedule 07.01.2015    source источник
comment
Нет. Используйте только один из них.   -  person    schedule 07.01.2015
comment
Оба они эквивалентны auto y(std::move(x)), который не выполняет переадресацию, а просто приводит к ссылке rvalue. Помните, что std::forward<T>() — это условное приведение к rvalue- или lvalue-ссылке (в зависимости от категории значения), а std::move() — это безусловное приведение к rvalue-ссылке.   -  person 0x499602D2    schedule 07.01.2015


Ответы (2)


move будет достаточно, если вы хотите переместиться независимо от категории значения аргумента.
forward в этом случае является излишним, так как move(forward(x)) всегда является значением r, независимо от того, что такое forward(x).

Если вы хотите двигаться только в зависимости от того, является ли аргумент bar rvalue, вы должны использовать forward сам по себе, который распространяет категорию значения.

person Columbo    schedule 07.01.2015
comment
Теперь, несмотря на то, что вызов forward излишен, не является ли прототип move технически универсальной ссылкой, которая предложила форвард? - person wyer33; 07.01.2015
comment
@ wyer33 Просто представьте move как функцию, которая возвращает значение r, ссылающееся на свой аргумент. И представьте forward как функцию, которая возвращает ссылку lvalue или rvalue, ссылающуюся на свой аргумент. Разница, которую forward вносит в выражение, если таковая имеется, в любом случае будет устранена move. - person Columbo; 07.01.2015

/!\ ВНИМАНИЕ /!\

Использование std::move для универсальной ссылки может быть очень плохой идеей, и настоятельно рекомендуется избегать:

auto name = getName(); // std::string getName();
bar(name);
// 'name' value has been moved... And its value now is unknown, empty at best.

move(forward(x)) — это плохой стиль, и его не следует использовать.

Вы должны использовать std::move для ссылок rvalue и std::forward для универсальных ссылок. См. формальные определения.

auto&& является универсальной ссылкой, поэтому вы должны написать:

void bar(auto&& x) {
    auto y(std::forward<decltype(x)>(x));
}
person Six    schedule 07.01.2015
comment
auto как аргумент функции? Какую версию C++ вы используете, C++21? - person Viktor Sehr; 07.01.2015
comment
Six60r: это сокращенная функция, которая не является частью стандарта (пока), @ViktorSehr fyi - person Piotr Skotnicki; 07.01.2015