реализация std::move

Я получил следующий фрагмент из Майкрософт

template <typename T> struct RemoveReference {
     typedef T type;
};

template <typename T> struct RemoveReference<T&> {
     typedef T type;
};

template <typename T> struct RemoveReference<T&&> {
     typedef T type;
};

template <typename T> typename RemoveReference<T>::type&& Move(T&& t) {
    return t;
}

...

remote_integer x = frumple(5);
remote_integer&& x1 = Move(x);

и я получаю сообщение об ошибке "ошибка C2440: 'return': невозможно преобразовать из 'remote_integer' в 'remote_integer &&'"

что-то изменилось в компиляторах? С std::move все идет как надо.


person Yola    schedule 08.09.2011    source источник
comment
Move принимает только rvalue, x — это lvalue. Вы должны использовать для этого stdmove (нижний регистр).   -  person RedX    schedule 08.09.2011
comment
social.msdn.microsoft .com/Forums/en-US/vs2010ctpcpp/thread/ — Джонатан Кейвз (команда компилятора Visual C++) пишет реализацию std::move, аналогичную моему Move. А Move я взял с сайта Microsoft, ссылка в сообщении с вопросом? и там все правильно, а в вк10 не работает.   -  person Yola    schedule 08.09.2011
comment
template ‹typename T› typename RemoveReference‹T›::type&& Move(T&& t) { return (RemoveReference‹T›::type&&)t; } - теперь все работает нормально, тут что-то с приведением типов.   -  person Yola    schedule 08.09.2011
comment
Теперь я понимаю вашу проблему, вы скопировали ее с сайта. Вы должны использовать std::move, указанный в заголовке утилит. Его реализация (как и ваше исправление) // TEMPLATE FUNCTION move template<class _Ty> inline typename tr1::_Remove_reference<_Ty>::_Type&& move(_Ty&& _Arg) { return ((typename tr1::_Remove_reference<_Ty>::_Type&&)_Arg); }   -  person RedX    schedule 08.09.2011
comment
Да, я сделал это после того, как разобрался с реализацией служебного модуля))) Спасибо   -  person Yola    schedule 08.09.2011
comment
Из любопытства, почему вы пытаетесь написать собственную реализацию std::move?   -  person Daniel Trebbien    schedule 08.09.2011
comment
@Red: Move принимает значение lvalue и преобразует его в значение x. Нет смысла передавать rvalue в move, так как rvalue будет привязано к ссылке rvalue без него.   -  person Potatoswatter    schedule 08.09.2011


Ответы (1)


Причина, по которой ваш Move не работает, заключается в том, что t всегда равно lvalue (даже когда T&& разрешается, скажем, в int&&). Хотя это может показаться странным, именованные ссылки rvalue на самом деле являются lvalue.

При возврате из вашего Move вы пытаетесь неявно привязать lvalue к ссылке rvalue, что запрещено стандартом (§8.5.3). Как отмечено в комментариях, вы должны явно привести t к ссылке rvalue.

Соответствующими частями стандарта являются §5/4 и §5/5, но я собираюсь процитировать примечание §5/6, которое хорошо суммирует это:

В общем, результатом этого правила является то, что именованные ссылки rvalue обрабатываются как lvalue, а неименованные ссылки rvalue на объекты обрабатываются как xvalue; Ссылки rvalue на функции обрабатываются как lvalue независимо от того, именованы они или нет.

Правильная реализация действительно:

template <typename T>
typename std::remove_reference<T>::type&& move(T&& t)
{
  return static_cast<typename std::remove_reference<T>::type&&>(t);
}

Насколько я помню, этот код был действителен в более ранних версиях. Но поскольку правила изменились, теперь вы должны предоставить явное приведение типов (то же самое относится и к std::forward).

person Vitus    schedule 08.09.2011