
On 5/30/2010 11:46 PM, Thomas Klimpel wrote:
Jeffrey Lee Hellrung wrote:
Thomas Klimpel wrote:
All that is needed to to wrap its type declaration with the BOOST_MOVE_ASSIGNMENT_WRAPPER macro. [snip]
Do you find this preferable to simply explicitly defining the copyassignment operator in the enclosing class?
The enclosing class might simply want to use the compiler generated copy constructor and copy assignment operator, for maintenance reasons. Another point is the behavior on compilers with rvalue references, as one of the goals of boost.move is to allow to write code that works on compilers with and without rvalue references, without scarifying the performance on new compilers for the compatibility with old compilers.
Fair enough. Either way, if boost::container::vector uses "optimal" move emulation, one won't be able to just drop it into an existing class without some additional modifications (e.g., using this move_assignment_wrapper, or defining an explicit copy assignment operator). And, in fact, using move_assignment_wrapper or defining a copy assignment operator can each happen conditionally, predicated on BOOST_NO_RVALUE_REFERENCES *and* on whether the boost::container::vector instance (or whatever member object we're concerned about) really does force an auto-generated copy assignment operator with signature operator=(T&). For example: T& operator=( typename boost::mpl::if_< enclosing_has_normal_autogen_copy_assign< vector<T> >, dummy_t, const T& >::type other) { ... } I only suggested to explicitly define the copy assignment operator because that seems like the "natural" resolution, in general, if the compiler fails the generate the correct one...
Apart from that, you are right in that the enclosing class could simply define TYPE& operator=(TYPE t) and be freed of all problems, without using the BOOST_MOVE_ASSIGNMENT_WRAPPER macro.
But as we are discussing the question whether classes like boost::container::vector should use the optimized move emulation, the exact impact on the enclosing class is quite important.
By "exact impact", you mean the "recommended resolution" to define, implicitly or explicitly, a standard copy assignment operator in the enclosing class...?
However, my position on breaking move-assignment from temporaries for the non-optimized mode remains that this is not a reasonable option, especially considering that it would be a serious regression with respect to the Adobe Move Library.
Is this a position based on technical semantics, rather than practical semantics? Because I believe even the non-optimized emulation should effectively move-assign from temporaries via RVO...
If it were not practical semantics, it wouldn't be a serious regression. The practical problem is the following: If the "move enabled" class defines "TYPE& operator=(const TYPE& t)", then the "TYPE& operator=(BOOST_RV_REF(&) t)" overload won't kick in for move assignment from temporaries on C++03 compilers, as "TYPE& operator=(const TYPE& t)" is a better match. It also cannot define a "TYPE& operator=(TYPE t)" overload in addition to "TYPE& operator=(const TYPE& t)" (this would be ambiguous), so RVO can also no longer kick in.
The alternative is to just define "TYPE& operator=(TYPE t)", but Ion doesn't like this for classes like boost::container::vector, as this copy assignment operator cannot reuse existing resources. So his proposed non-optimized mode sacrificed move-assign from temporaries on C++03 compilers, to avoid non-optimal code on new compilers in C++0x mode.
Ah, okay, I was thinking of the distinction between the 2 move emulation modes described in the proposed Boost.Move documentation, neither of which use a copy assignment operator with signature operator=(const T&). If I understand correctly, optimal move emulation for boost::container::vector is the best choice if we ignore the effect on (future) enclosing classes. Are you/we necessarily against just going with this, documenting the fact that enclosing classes will have to deal with the non-standard compiler-generated copy assignment operator (either by defining it explicitly, perhaps conditionally; or wrapping member vars in a wrapper, also perhaps conditionally)? We don't have any backwards compatibility concerns, since boost::container::vector is not actually released yet, right? - Jeff