Boost.Moveоснован на макросах, которые расширены до истинных rvalue-ссылок в компиляторах C++0x и эмулированных rvalue-ссылочных классах и операторах преобразования в компиляторах C++03.
В компиляторах C++03Boost.Moveопределяет класс<::boost::rv
>:
template <class T>
class rv : public T
{
rv();
~rv();
rv(rv const&);
void operator=(rv const&);
};
который может быть преобразован в подвижный базовый класс (обычный C++, полученный в базовое преобразование). Когда пользователи помечают свои классы как<BOOST_MOVABLE_BUT_NOT_COPYABLE
>или<BOOST_COPYABLE_AND_MOVABLE
>, эти макросы определяют операторов преобразования для ссылок на<::boost::rv
>:
#define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\
public:\
operator ::boost::rv<TYPE>&() \
{ return *static_cast< ::boost::rv<TYPE>* >(this); }\
operator const ::boost::rv<TYPE>&() const \
{ return static_cast<const ::boost::rv<TYPE>* >(this); }\
private:\
<BOOST_MOVABLE_BUT_NOT_COPYABLE
>также объявляет частный конструктор копий и назначение.<BOOST_COPYABLE_AND_MOVABLE
>определяет конструктор неконст-копий<TYPE
&operator=(TYPE&)
>, который пересылает на конст-версию:
#define BOOST_COPYABLE_AND_MOVABLE(TYPE)\
public:\
TYPE& operator=(TYPE &t)\
{ this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}\
В компиляторах C++0x<BOOST_COPYABLE_AND_MOVABLE
>ничего не расширяется и<BOOST_MOVABLE_BUT_NOT_COPYABLE
>объявляет конструктора копий и оператора ассигмента частными.
Когда пользователи определяют<BOOST_RV_REF
>перегрузку конструктора/назначения копии, в компиляторах C++0x она расширяется до эталонной перегрузки rvalue<T&&
>, а в компиляторах C++03 — до<::boost::rv<T>
&
>перегрузки:
#define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \
Когда пользователи определяют перегрузку<BOOST_COPY_ASSIGN_REF
>, она расширяется до обычной перегрузки копирования<const
T&
>в компиляторах C++0x и до<const
::boost::rv&
>перегрузки в компиляторах C++03:
#define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&
Как видно, вBoost.Moveгенерирует эффективный и чистый код для семантики движения C++0x, не изменяя при этом перегрузку разрешения. Для компиляторов C++03 при выполнении разрешения перегрузки используются следующие привязки:
- a) неконстовые значения (например, временные значения), связываемые с<
::boost::rv<TYPE>&
> - b) const rvalue и lvalues, связываются с<
const
::boost::rv<TYPE>&
> - c) неконстовые значения l (например, неконстовые ссылки) связываются с<
TYPE&
>
Библиотека не определяет эквивалент<BOOST_COPY_ASSIGN_REF
>для построения копий (скажем,<BOOST_COPY_CTOR_REF
>), потому что почти все современные компиляторы реализуют RVO, и это намного эффективнее любой эмуляции перемещения.<move
>только бросает<TYPE&
>в<::boost::rv<TYPE>&
>.
Вот пример, который показывает, как различные объекты rlvalue связываются с<::boost::rv
>ссылками при наличии трех перегрузок и операторов преобразования в компиляторах C++03:
#include <boost/move/core.hpp>
#include <iostream>
class sink_tester
{
public:
operator ::boost::rv<sink_tester>&()
{ return *static_cast< ::boost::rv<sink_tester>* >(this); }
operator const ::boost::rv<sink_tester>&() const
{ return *static_cast<const ::boost::rv<sink_tester>* >(this); }
};
sink_tester rvalue() { return sink_tester(); }
const sink_tester const_rvalue() { return sink_tester(); }
sink_tester & lvalue() { static sink_tester lv; return lv; }
const sink_tester & const_lvalue() { static const sink_tester clv = sink_tester(); return clv; }
void sink(::boost::rv<sink_tester> &) { std::cout << "non-const rvalue catched" << std::endl; }
void sink(const ::boost::rv<sink_tester> &){ std::cout << "const (r-l)value catched" << std::endl; }
void sink(sink_tester &) { std::cout << "non-const lvalue catched" << std::endl; }
int main()
{
sink(const_rvalue());
sink(const_lvalue());
sink(lvalue());
sink(rvalue());
return 0;
}