
David Abrahams wrote:
On Nov 16, 2009, at 7:46 AM, David Abrahams wrote:
On Sep 8, 2009, at 5:52 AM, Ion GaztaƱaga wrote:
We need a third alternative: a new overload set that maintains "const T &" and properly catches non-const rvalues. I think we have it:
define one copy assignment operator in terms of swap. Copy elision makes it nearly as fast as a move, and we don't get an operator=(T&) infection in derived classes.
I have no problem with requiring move-enablers to supply a swap.
In fact, I don't even think we need to do that. This seems to work pretty well:
#define BOOST_COPYABLE_AND_MOVABLE(TYPE)\ public:\ TYPE& operator=(TYPE t)\ { return this->operator=(static_cast< ::boost::rv<TYPE>&>(t)); } \ public:\ operator ::boost::rv<TYPE>&() \ { return *reinterpret_cast< ::boost::rv<TYPE>* >(this); }\ operator const ::boost::rv<TYPE>&() const \ { return *reinterpret_cast<const ::boost::rv<TYPE>* >(this); }\ private:\ //
-- David Abrahams BoostPro Computing http://boostpro.com
I think this was similar to what Ion had before, no? Only the user had to explicitly provide the copy assignment (which accepted a by-value parameter). The downside is the double copy of non-movable objects during copy assignment when no copy elision can kick in: copyable_and_movable x(...); copyable_and_movable y(...); x = y; // non-movable stuff in y is copied twice, right? In fact, copyable_and_movable may not even have anything movable in it (if it's templated, e.g., std::pair), so operator=(T) does twice as much work as operator=(const T&) ! The "current" solution (that which is in the sandbox, using BOOST_COPY_ASSIGN_REF) avoids this double copying at the expense auto-generating an operator= that accepts non-const references. Also, as Ion mentioned, currently acquired resources can't be reused if your copy assignment signature accepts by value. That said, I think I'd prefer a by-value operator=, as it seems reasonably close to optimal and gives better semantic behavior regarding auto-generated operator=. Is there some way to generate a (close to) optimal operator= overload for std::pair? I.e., the BOOST_COPYABLE_AND_MOVABLE macro provides one of operator=(const pair&) or operator=(pair) depending on some compiler time boolean value? I'm thinking: template< class T0, class T1 > pair { private: static const bool should_move = T0::should_move || T1::should_move; // obviously not exactly this but the intent should be clear... BOOST_COPYABLE_AND_MOVABLE( pair ) // refers to should_move to decide whether to generate operator=(const pair&) or operator=(pair) public: T0 first; T1 second; }; Something like: template< class T > typename boost::enable_if_c< boost::is_same< T, pair >::value && should_move, pair& >::type operator=(T x); template< class T > typename boost::enable_if_c< boost::is_same< T, pair >::value && !should_move, pair& >::type operator=(const T& x); Is this worth pursuing? Also, the conversion operator to const rv<T>& is a must, as it allows all functions sans T::operator= to be overloaded on const rv<T>&, T&, and rv<T>& to truly capture rvalues by reference. - Jeff