#define BOOST_BINARY_OPERATOR( NAME, OP ) \
template <class T, class U = T, class B = detail::empty_base<T> > \
struct NAME##_commutative : B \
{ \
friend T operator OP( const T& lhs, const U& rhs ) { T nrv(lhs); nrv OP##= rhs; return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, const U& rhs ) { return boost::move(lhs OP##= rhs); } \
friend T operator OP( const T& lhs, BOOST_RV_REF(U) rhs ) { T nrv(lhs); nrv OP##= boost::move(rhs); return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, BOOST_RV_REF(U) rhs ) { return boost::move(lhs OP##= boost::move(rhs)); } \
friend T operator OP( const U& lhs, const T& rhs ) { T nrv(rhs); nrv OP##= lhs; return nrv; } \
friend T operator OP( const U& lhs, BOOST_RV_REF(T) rhs ) { return boost::move(rhs OP##= lhs); } \
friend T operator OP( BOOST_RV_REF(U) lhs, const T& rhs ) { T nrv(rhs); nrv OP##= boost::move(lhs); return nrv; } \
friend T operator OP( BOOST_RV_REF(U) lhs, BOOST_RV_REF(T) rhs ) { return boost::move(rhs OP##= boost::move(lhs)); } \
}; \
\
template <class T, class B> \
struct NAME##_commutative <T, T, B> : B \
{ \
friend T operator OP( const T& lhs, const T& rhs ) { T nrv(lhs); nrv OP##= rhs; return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, const T& rhs ) { return boost::move(lhs OP##= rhs); } \
friend T operator OP( const T& lhs, BOOST_RV_REF(T) rhs ) { return boost::move(rhs OP##= lhs); } \
friend T operator OP( BOOST_RV_REF(T) lhs, BOOST_RV_REF(T) rhs ) { return boost::move(lhs OP##= boost::move(rhs)); } \
}; \
\
template <class T, class U = T, class B = detail::empty_base<T> > \
struct NAME : B \
{ \
friend T operator OP( const T& lhs, const U& rhs ) { T nrv(lhs); nrv OP##= rhs; return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, const U& rhs ) { return boost::move(lhs OP##= rhs); } \
friend T operator OP( const T& lhs, BOOST_RV_REF(U) rhs ) { T nrv(lhs); nrv OP##= boost::move(rhs); return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, BOOST_RV_REF(U) rhs ) { return boost::move(lhs OP##= boost::move(rhs)); } \
}; \
\
template <class T, class U, class B = detail::empty_base<T> > \
struct NAME##_left : B \
{ \
friend T operator OP( const U& lhs, const T& rhs ) { T nrv(lhs); nrv OP##= rhs; return nrv; } \
friend T operator OP( BOOST_RV_REF(U) lhs, const T& rhs ) { T nrv(boost::move(lhs)); nrv OP##= rhs; return nrv; } \
friend T operator OP( const U& lhs, BOOST_RV_REF(T) rhs ) { T nrv(lhs); nrv OP##= boost::move(rhs); return nrv; } \
friend T operator OP( BOOST_RV_REF(U) lhs, BOOST_RV_REF(T) rhs ) { T nrv(boost::move(lhs)); nrv OP##= boost::move(rhs); return nrv; } \
}; \
\
template <class T, class B> \
struct NAME <T, T, B> : B \
{ \
friend T operator OP( const T& lhs, const T& rhs ) { T nrv(lhs); nrv OP##= rhs; return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, const T& rhs ) { return boost::move(lhs OP##= rhs); } \
friend T operator OP( const T& lhs, BOOST_RV_REF(T) rhs ) { T nrv(lhs); nrv OP##= boost::move(rhs); return nrv; } \
friend T operator OP( BOOST_RV_REF(T) lhs, BOOST_RV_REF(T) rhs ) { return boost::move(lhs OP##= boost::move(rhs)); } \
};