Я наблюдал за Скоттом Майерсом на Universal Libraries на конференции С++ и Beyond 2012, и все имеет смысл до сих пор. Тем не менее, член аудитории задает вопрос примерно через 50 минут, о котором мне также было интересно. Мейерс говорит, что он не заботится о ответе, потому что он не идиоматичен и глупо его ум, но меня все еще интересует.
Представленный код выглядит следующим образом:
// Typical function bodies with overloading:
void doWork(const Widget& param) // copy
{
// ops and exprs using param
}
void doWork(Widget&& param) // move
{
// ops and exprs using std::move(param)
}
// Typical function implementations with universal reference:
template <typename T>
void doWork(T&& param) // forward => copy and move
{
// ops and exprs using std::forward<T>(param)
}
Точка заключается в том, что, когда мы берем ссылку на rvalue, мы знаем, что у нас есть rvalue, поэтому нам нужно std::move
сохранить тот факт, что это rvalue. Когда мы берем универсальную ссылку (T&&
, где T
- выведенный тип), мы хотим, чтобы std::forward
сохранял тот факт, что это могло быть lvalue или rvalue.
Итак, возникает вопрос: поскольку std::forward
сохраняет ли значение, переданное в функцию, либо значение lvalue, либо rvalue, а std::move
просто передает свой аргумент в rvalue, можно ли просто использовать std::forward
всюду? Будет ли std::forward
вести себя как std::move
во всех случаях, когда мы будем использовать std::move
, или есть некоторые важные отличия в поведении, которые упускаются из-за обобщения Мейерса?
Я не предполагаю, что кто-то должен это делать, потому что, как правильно говорит Мейерс, он полностью не идиоматичен, но также является допустимым использованием std::move
:
void doWork(Widget&& param) // move
{
// ops and exprs using std::forward<Widget>(param)
}