
[My original reply went directly to Ion, due to me being cc'ed in the original email. Hence forwarding... (pun intended)] -------- Original Message -------- Subject: Re: [move] You can do it better: implementing push_back and handling implicit conversions Date: Tue, 08 Mar 2011 17:23:58 -0800 From: Jeffrey Lee Hellrung, Jr. <jhellrung@ucla.edu> Reply-To: jhellrung@ucla.edu To: Ion Gaztañaga <igaztanaga@gmail.com> On 3/8/2011 1:57 PM, Ion Gaztañaga wrote:
Hi to all,
Are you a C++ expert? Do you like Boost.Move? I have a challenge for you.
During Boost.Move review, Jeffrey Lee Hellrung suggested adding "techniques to capture (implicitly created) rvalues with emulated rvalue references in C++03, e.g., for push_back, when you have knowledge of the types of objects you want to capture".
Yes, you know, I do seem to remember suggesting that...
I've worked on this problem these days and the solution is less than obvious (several compilers have has problems with ::boost::is_convertible and non-copyable types). I found a solution (attached test and required boost/move/move.hpp header) after several tries but it's complex (it needs several overloads and enable_if tricks) but I'm sure boosters will find a easier solution ;-)
Yes, a bit more complex than the solution I've been using for a while now (rough idea attached and explained below).
Current solution seems to work on these compilers: MSVC 7.1, 8.0, 9.0, Intel 11.0, GCC 4.3.4, 4.4, 4.4 c++0x mode, 4.5, 4.5 c++0x mode.
I've gotten your test cpp to compile and run with no assertion failures on MSVC9 (with a slight modification to assertions; see below), and I've used this same technique on gcc, but I don't work nearly as much on gcc, so it may be that some corner cases fail.
Problem: MSVC 10.0 (Visual 2010) with real rvalue references seems to have bugs and does not compile the test. I can't find a workaround, a future Service Pack might solve these errors, but maybe we should stick to emulation code in this compiler, unless someone could shed some light on this, of course.
Well...that sucks :(
Waiting your proposals,
Ion
Okay, here is the summary. Ion, I count 5 overloads of push_back in C++03 and 4 overloads in C++0x for your solution. I believe one can get by with just 3 overloads in C++03, and 1 in C++0x, but the path to "T construction" in my solution is a little bit different than yours. I delay any T construction until the placement new statement in priv_push_back. I don't know what your requirements are in general, but for push_back, I think this should be fine. The solution I sent you has maybe a slight disadvantage over yours in that conversion errors would likely end up pointing to priv_push_back, but if this is a concern, the template overloads of push_back can be restricted (further) with enable_if (I think). This has the effect that push_back'ing a conversion_source object x directly constructs the storage with x, rather than constructing a temporary and copying or constructing a temporary and moving. For push_back, it seems this is definitely desirable, and I'm having a hard time coming up with a situation where it is *not* desirable to delay the construction as long as possible. In any case, this explains the change in your assertions. I also added a Default value to the ConstructionType enum because...it was bugging me ;) The 3 overloads in C++03 are basically: // captures const lvalues and rvalues that are *not* T template< class U > typename boost::disable_if< is_same_sans_const_sans_reference<U,T> >::type push_back(const U& x) { ... as_lvalue(x) ... } // captures non-const lvalues and T lvalues template< class U > void push_back(U& x) { ... x ... } typedef typename add_reference_add_const< typename add_rvalue_reference<T>::type >::type rv_param_type; // captures T rvalues (if T is movable) void push_back(rv_param_type x) { ... x ... } In C++0x, a single overload is sufficient, I think: template< class U > void push_back(U&& x) { ... boost::forward<U>(x) ... } Let me know what you think of this framework. - Jeff