Boost.Move 基于宏,这些宏在 C++0x 编译器中展开为真正的右值引用,在 C++03 编译器中则模拟右值引用类和转换运算符。
在 C++03 编译器中,Boost.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:\ //More stuff...
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;}\ //More stuff...
在 C++0x 编译器中,BOOST_COPYABLE_AND_MOVABLE
展开为空,而 BOOST_MOVABLE_BUT_NOT_COPYABLE
声明复制构造函数和赋值运算符为私有。
当用户定义 BOOST_RV_REF
复制构造函数/赋值运算符的重载时,在 C++0x 编译器中,它被展开为右值引用(T&&
)重载,在 C++03 编译器中,它被展开为 ::boost::rv<T> &
重载
#define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \
当用户定义 BOOST_COPY_ASSIGN_REF
重载时,它在 C++0x 编译器中被展开为通常的复制赋值(const T &
)重载,在 C++03 编译器中被展开为 const ::boost::rv &
重载
#define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&
如所见,Boost.Move 为 C++0x 移动语义生成高效且简洁的代码,而无需修改任何重载解析。对于 C++03 编译器,当执行重载解析时,这些是绑定
::boost::rv< TYPE >&
const ::boost::rv< TYPE >&
TYPE&
该库没有为复制构造函数定义等效于 BOOST_COPY_ASSIGN_REF
的宏(例如,BOOST_COPY_CTOR_REF
),因为几乎所有现代编译器都实现了 RVO,这比任何移动模拟都更高效。move
只是将 TYPE &
转换为 ::boost::rv<TYPE> &
。
这是一个示例,演示了在 C++03 编译器中存在三个重载和转换运算符的情况下,不同的右值对象如何绑定到 ::boost::rv
引用
#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; }