Трябва ли 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)) винаги е rvalue, без значение какво е forward(x).

Ако искате да преместите само в зависимост от това дали аргументът за bar е rvalue, трябва да използвате forward самостоятелно, което разпространява категорията стойност.

person Columbo    schedule 07.01.2015
comment
Сега, въпреки че извикването на forward е излишно, не е ли прототипът за move технически универсална препратка, която предложи напред? - person wyer33; 07.01.2015
comment
@wyer33 Просто си представете move като функция, която връща rvalue, отнасяща се до своя аргумент. И си представете 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