...one of the most highly
regarded and expertly designed C++ library projects in the
world.
— Herb Sutter and Andrei
Alexandrescu, C++
Coding Standards
Boost.Move is based on macros that are expanded to true rvalue references in C++0x compilers and emulated rvalue reference classes and conversion operators in C++03 compilers.
In C++03 compilers Boost.Move defines a class
named ::boost::rv
:
template <class T> class rv : public T { rv(); ~rv(); rv(rv const&); void operator=(rv const&); };
which is convertible to the movable base class (usual C++ derived to base conversion).
When users mark their classes as BOOST_MOVABLE_BUT_NOT_COPYABLE
or BOOST_COPYABLE_AND_MOVABLE
,
these macros define conversion operators to references to ::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:\ //More stuff...
BOOST_MOVABLE_BUT_NOT_COPYABLE
also declares a private copy constructor and assignment. BOOST_COPYABLE_AND_MOVABLE
defines a non-const copy constructor TYPE
&operator=(TYPE&)
that forwards to a const version:
#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;}\ //More stuff...
In C++0x compilers BOOST_COPYABLE_AND_MOVABLE
expands to nothing and BOOST_MOVABLE_BUT_NOT_COPYABLE
declares copy constructor and assigment operator private.
When users define the BOOST_RV_REF
overload of a copy constructor/assignment, in C++0x compilers it is expanded
to a rvalue reference (T&&
)
overload and in C++03 compilers it is expanded to a ::boost::rv<T>
&
overload:
#define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \
When users define the BOOST_COPY_ASSIGN_REF
overload, it is expanded to a usual copy assignment (const
T &
)
overload in C++0x compilers and to a const
::boost::rv &
overload in C++03 compilers:
#define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&
As seen, in Boost.Move generates efficient and clean code for C++0x move semantics, without modifying any resolution overload. For C++03 compilers when overload resolution is performed these are the bindings:
::boost::rv< TYPE >&
const
::boost::rv< TYPE >&
TYPE&
The library does not define the equivalent of BOOST_COPY_ASSIGN_REF
for copy construction (say, BOOST_COPY_CTOR_REF
)
because nearly all modern compilers implement RVO and this is much more efficient
than any move emulation. move
just casts TYPE &
into ::boost::rv<TYPE> &
.
Here's an example that demostrates how different rlvalue objects bind to ::boost::rv
references in the presence of three overloads
and the conversion operators in C++03 compilers:
#include <boost/move/core.hpp> #include <iostream> class sink_tester { public: //conversions provided by BOOST_COPYABLE_AND_MOVABLE 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); } }; //Functions returning different r/lvalue types 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; } //BOOST_RV_REF overload void sink(::boost::rv<sink_tester> &) { std::cout << "non-const rvalue catched" << std::endl; } //BOOST_COPY_ASSIGN_REF overload void sink(const ::boost::rv<sink_tester> &){ std::cout << "const (r-l)value catched" << std::endl; } //Overload provided by BOOST_COPYABLE_AND_MOVABLE void sink(sink_tester &) { std::cout << "non-const lvalue catched" << std::endl; } int main() { sink(const_rvalue()); //"const (r-l)value catched" sink(const_lvalue()); //"const (r-l)value catched" sink(lvalue()); //"non-const lvalue catched" sink(rvalue()); //"non-const rvalue catched" return 0; }