Добрый день!
Еще вчера я честно думал, что разобрался как работают rvalue references в C++11. Думал до тех пор, пока не наткнулся на грабли.
Итак, я предлагаю размять мозги и попробовать написать функцию move_if_rr. Такой себе тест на понимание: успех засчитывается за функцию, которая работает правильно при условии, что Вы ее ни разу не отлаживали. Детали задания под катом.
Итак, условие.
Пусть, есть следующий код:
Функции dummy нужны только, для того, чтобы разъяснить семантику move_if_rr (ниже по тексту).
Приведенный выше код не несет никакой смысловой нагрузки, все совпадения считать случайными.
Необходимо написать функцию move_if_rr, удовлетворяющую следующим правилам:
Если закомментированный forward в Container.Fwd, вызовет dummy, помеченную как move:
* Использование move_if_rr должно приводить к вызову move-assignment поля member.
Если закомментированный forward в Containerю.Fwd, вызовет dummy, помеченную как copy:
* Использование move_if_rr должно приводить к вызову copy-assignment поля member.
Оба правила предполагают, что в качестве аргумента Container.Fwd был передан тип Container.
Решения ожидаются в комментариях.
UPD1. Чтобы выложить код можно использовать highlight.hohli.com (нужно поставить галочку «Use font tag (for Habrahabr)»)
UPD2. Для тех кто не понял, что такое move_if_rr:
Это расширенная версия std::forward: Используя std::forward нельзя указать в качестве шаблонного аргумента один тип, а в качестве параметра — другой, move_if_rr решает именно эту задачу. Зачем?
потому что если мне передали некий тип по rvalue ссылке, то и все внутренние его компоненты тоже можно рассматривать как переданные по rvalue ссылке. Только вот как это объяснить компилятору, если я не указывал явно как мне передавали этот самый некий тип, а использовал стандартную forward-нотацию?
Пример:
Допустим была вот такая функция:
UPD 3. Условие немного перефразировано, т.к. предыдущая формулировка позволяла цепляться к семантике конструкторов (вместо Fwd использовался конструктор).
UPD 4. Проверить решение можно вставив его в начало этого кода, полностью корректный вариант можно найти тут, есть также вариант от SergX — без использования mpl
Еще вчера я честно думал, что разобрался как работают rvalue references в C++11. Думал до тех пор, пока не наткнулся на грабли.
Итак, я предлагаю размять мозги и попробовать написать функцию move_if_rr. Такой себе тест на понимание: успех засчитывается за функцию, которая работает правильно при условии, что Вы ее ни разу не отлаживали. Детали задания под катом.
Итак, условие.
Пусть, есть следующий код:
template< class U >Container намеренно сделан шаблонным, чтобы реальный тип member был неизвестен.
class Container
{
U member;
public:
U &Get(){ return member; }
const U &Get() const{ return member; }
public:
template< class T > void dummy( const Container< T > & ); // copy
template< class T > void dummy( Container< T > && ); // move
public:
// Ожидается, что T - это нечто совместимое с Container
template< class T >
void Fwd( T &&rr )
{
member = move_if_rr< T >( rr.Get() );
// dummy( std::forward< T >( rr ) )
}
};
Функции dummy нужны только, для того, чтобы разъяснить семантику move_if_rr (ниже по тексту).
Приведенный выше код не несет никакой смысловой нагрузки, все совпадения считать случайными.
Необходимо написать функцию move_if_rr, удовлетворяющую следующим правилам:
Если закомментированный forward в Container.Fwd, вызовет dummy, помеченную как move:
* Использование move_if_rr должно приводить к вызову move-assignment поля member.
Если закомментированный forward в Containerю.Fwd, вызовет dummy, помеченную как copy:
* Использование move_if_rr должно приводить к вызову copy-assignment поля member.
Оба правила предполагают, что в качестве аргумента Container.Fwd был передан тип Container.
Решения ожидаются в комментариях.
UPD1. Чтобы выложить код можно использовать highlight.hohli.com (нужно поставить галочку «Use font tag (for Habrahabr)»)
UPD2. Для тех кто не понял, что такое move_if_rr:
Это расширенная версия std::forward: Используя std::forward нельзя указать в качестве шаблонного аргумента один тип, а в качестве параметра — другой, move_if_rr решает именно эту задачу. Зачем?
потому что если мне передали некий тип по rvalue ссылке, то и все внутренние его компоненты тоже можно рассматривать как переданные по rvalue ссылке. Только вот как это объяснить компилятору, если я не указывал явно как мне передавали этот самый некий тип, а использовал стандартную forward-нотацию?
Пример:
Допустим была вот такая функция:
template< class T >И тут что-то изменили в программе, и в нее стал приходить композитный тип (старый тип в нем есть как поле). Как передать это поле с форвардингом, как и раньше? C move_if_rr это выглядит так:
void f( T &&rr )
{
SendData( std::forward< T >( rr ) );
}
template< class T >
void f( T &&rr )
{
SendData( std::move_if_rr< T >( rr.GetSomeElement() ) );
}
UPD 3. Условие немного перефразировано, т.к. предыдущая формулировка позволяла цепляться к семантике конструкторов (вместо Fwd использовался конструктор).
UPD 4. Проверить решение можно вставив его в начало этого кода, полностью корректный вариант можно найти тут, есть также вариант от SergX — без использования mpl