
Hi to all, I've uploaded a new version of the move emulation library to sandbox. I've put it temporarily in "move_semantics" folder to avoid overwriting current move code. I've put some quickbook documentation whose introduction is based in the article "A Brief Introduction to Rvalue References" by Hinnant, Stroustrup, Kozicki. http://svn.boost.org/svn/boost/sandbox/libs/move_semantics/index.html The library needs specially modified Interprocess containers (and Intrusive because of dependences), which I've also uploaded to sandbox. The examples show how movable only values can be inserted into containers. For those that don't like svn sandbox (I'm one of them) I've also put the code and the documentation here: http://www.drivehq.com/web/igaztanaga/move_semantics.zip And online documentation also here: http://www.drivehq.com/web/igaztanaga/libs/move_semantics/ The documentation is not in english, it's in my own english dialect so be careful when reading ;-) Patches and corrections welcome. I've documented some functions to create a little boostbook reference. I've invested some precious time in the library and testing different approaches to see if it plays well with containers but I would like to hear some comments on whether the direction is acceptable and if I should spend more time on it. If someone else with more time wants to continue the library, please do it! ;-) I've personally added to the library all that I've seen useful for move-aware containers, so it might lack some features (move aware algorithms, for example). Anyway, my opinion is that we need some move library, better now than later even if it's too basic, so that we can unify all redundant move emulation that we already have in boost libraries. I hope this is a step in the right direction. Best, Ion

Ion, I've followed the discussions about move emulation because I badly need it (without waiting for c+0x), and I've looked at the solutions in Boost.Interprocess many times trying to reuse portions of it in my own code. However, it takes careful crafting to get it done right, and I've been worried about not being able to cover all test cases. Horrible things happens if code compiles that shouldn't or objects are not moved as intended. The macros provided in your Move emulation library is exactly what I was hoping for (BOOST_ENABLE_MOVE_EMULATION, BOOST_RV_REF), Used with move-aware containers where I can put move-aware homegrown objects would be extremely useful, immediately. If the updated versions of Interprocess and Intrusive are somewhat compatible with Boost 1.35 (I don't dare to upgrade to 1.38 at this time), I'd like to try out the library for production code (Windows, 64bit). I could probably devote a machine for regressiontests as well for my platform, if that helps. Regards, Christian

Ion Gaztañaga wrote:
Why is forwarding constructor specific? Shouldn't it work with any function? I suggest renaming BOOST_CONSTRUCT_FWD_REF to BOOST_FWD_REF and boost::forward_constructor to boost::forward. I suppose there is an issue to forward references vs const references. Is that why it's limited to constructors?
Those containers probably have little to do in the interprocess namespace. Maybe it's time to make them first-class boost citizens?
The documentation doesn't really mention what are the limits of the emulation, if there are any.

Hi, ----- Original Message ----- From: "Mathias Gaunard" <mathias.gaunard@ens-lyon.org> To: <boost@lists.boost.org> Sent: Wednesday, February 18, 2009 3:00 AM Subject: Re: [boost] [move] Library uploaded to sandbox Ion Gaztañaga wrote:
From which containers are you talking about? What do you mean by "make them first-class boost citizens"?
Best, Vicente

vicente.botet wrote:
From which containers are you talking about? What do you mean by "make them first-class boost citizens"?
The implementation of the standard containers that lies in the interprocess namespace. Those are standard conformant, but also support: - allocators with non-T* pointer type - move semantics - in-place construction In the beginning, they were written because most implementations of the standard containers do not allow allocators with special pointer types (which is explicitly allowed by the standard, unfortunately), which made them unable to be used with shared memory. However, it shouldn't be under interprocess, it should be in Boost.Containers, or Boost.STL or whatever good name one can come up with.

Mathias Gaunard wrote:
I renamed then just recently, because the emulation is was limited. It works for every function but it does not forward non-const references, so it's not intended to implement bind / function -like perfect forwarding. It fits quite well for in-place construction. To avoid this workaround we could adopt boost::ref as a the way to pass non-const references so that forward returns a non-const reference. I personally don't have any problem to limit forwarding to this, but maybe other library writers don't think the same. Eric kindly showed provided some C++03 perfect forwarding Boost.Preprocessor emulation code in but I'm too limited to implement more than really trivial preprocessor metaprogramming. And it could not find a way to it some easy to use, generic component that I could offer with Boost.Move. However I have some ideas to simplify a preprocessor-based perfect forwarding utility, with the help of some pre-preprocessing ;-): 1) We create a list of defines with parameters pre-preprocessed (created offline) up to a admissible number of parameters (maybe 5 which leads to 64 overloads per function) BOOST_PERFECT_FWD_ARG_0 const T0 & BOOST_PERFECT_FWD_ARG_1 T0 & BOOST_PERFECT_FWD_ARG_2 const T0 &, const T1 & BOOST_PERFECT_FWD_ARG_3 T0 &, const T1 & BOOST_PERFECT_FWD_ARG_4 const T0 &, T1 & //and so on BOOST_PERFECT_FWD_NUMPARAMS_0 1 BOOST_PERFECT_FWD_NUMPARAMS_1 1 BOOST_PERFECT_FWD_NUMPARAMS_2 2 BOOST_PERFECT_FWD_NUMPARAMS_3 2 BOOST_PERFECT_FWD_NUMPARAMS_4 2 //and so on 2) Have only a single preprocessor loop (since the previous pre-preprocessing unrolls the const non-const combination loop) that writes something like this (note that I have no Boost.PP idea so I'm, writing some imaginary PP functions named BOOST_IG_XXXX): #define BOOST_PP_LOCAL_MACRO(n)\ \ template<\ BOOST_PP_ENUM_PARAMS\ (BOOST_IG_PASTE(BOOST_PERFECT_FWD_NUMPARAMS_, n),\ class T)>\ void forward(someparam, BOOST_IG_PASTE(BOOST_PERFECT_FWD_ARG_0, n))\ {/**/}\ #define BOOST_PP_LOCAL_LIMITS (1, BOOST_PERFECT_FWD_MAX) #include BOOST_PP_LOCAL_ITERATE() Maybe this will also help with compile times but obviously, it won't avoid exponential overloading to achieve perfect forwarding in C++03. If any Boost.PP expert dares to write this, welcome. Boost.Move could offer the pre-preprocessed utilities BOOST_PERFECT_FWD_XXX and an easy guide to write perfect forwarding with the Boost.PP. But this is just a vague idea.
Those containers probably have little to do in the interprocess namespace. Maybe it's time to make them first-class boost citizens?
I have no problem to isolate them and put them somewhere in Boost provided binary compatibility is guaranteed so that Interprocess users don't break their code. However, I won't have time to add new features or document more than they are (after all, everybody knows have to use a container). As a side note, non-standard containers like flat_map (what an horrible name for an ordered vector, isn't it?) will be much more efficient with move semantics.
There are, of course. I'll add this information. Thanks for the comments, best, Ion

Hi Ion,
what is the differnet to Adobe's move library (http://stlab.adobe.com/group__move__related.html) ?? Regards, Olaf

Olaf Peter wrote:
what is the differnet to Adobe's move library (http://stlab.adobe.com/group__move__related.html) ??
It is based on rvalue references and can fallback to them, for one.

Olaf Peter wrote:
The emulation is different because Adobe's library "move" returns T: T move(T &t); This library (credits to David Abrahams) returns a pseudo-rvalue reference: boost::rv<T> & move(T &t); so there is a way to implement forwarding without any intermediate copy or move and to modify the original value instead of creating a temporary one. For example Adobe.Move containers need to implement push_back by value: push_back(T t); whereas with this library we can implement it in a more C++0x-like approach: push_back(const T &t); push_back(BOOST_RV_REF(T)t); which will provide an easier transition to C++0x code.
Regards, Olaf
Best, Ion

on Wed Feb 18 2009, Ion Gaztañaga <igaztanaga-AT-gmail.com> wrote:
Really, that was *my* idea?
...which they can do because they assume the existence of a swap for T. That's the classic "sink function" pattern, which "moves" from rvalues by relying on copy elision. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

David Abrahams wrote:
You posted the code... http://lists.boost.org/Archives/boost/2009/01/146922.php Regards, Ion

on Wed Feb 18 2009, Ion Gaztañaga <igaztanaga-AT-gmail.com> wrote:
Ah, yes. Very nice <pats self on back>. Thanks for carrying that idea through to completion! -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Ion Gaztañaga wrote:
You posted the code...
Oh, so that's actually how it works. How evil, yet very nice.

I think the doc_file_descriptor example should show how to create an object directly in the vector<file_descriptor> using emplace functions, as boost::move can't detect true rvalues as in c+0x. boost::interprocess::vector<file_descriptor> v; v.push_back(file_descriptor("filename")); // <- Fails v.emplace_back(""); // <- Works, of course Anyways, the move-emulation you submitted is immediately useful (together with the updated container library). I wish I had this years ago Best regards, Christian

2009/2/18 Mathias Gaunard <mathias.gaunard@ens-lyon.org>
The chosen overload is void vector<T>::push_back(const T& x), I don't think it's possible to detect a difference between foo(T()) -> const T& const T x; foo(x); -> const T& and one don't want to automatically be able to move const&. The following works, although a bit verbose v.push_back(const_cast<file_descriptor&>(file_descriptor(""))); / Christian

Mathias Gaunard writes:
Correction: If you have these overloads: push_back(const T &x); push_back(BOOST_RV_REF(T) x); Then 1 is chosen because derived to base conversion is stronger than the conversion operator. But if you disable const overload with enable_if<is_movable<T> > then you can do this: v.push_back(file_descriptor("filename")); but this will also work (and seems dangerous): file_descriptor f; v.push_back(f); //Note, no "move" In Interprocess containers I've chosen a more verbose and limited approach: //Catch by value works file_descriptor temp(get_file_descriptor()); //Now explicit move v.push_back(boost::move(temp)); You can also use a catch by value approach with this library: push_back(movable m); that will work with both: v.push_back(boost::move(temp)); v.push_back(movable()); The downside is that you always create a temporary and code will not conform to C++0x. As you mentioned, limitations of the library are not mentioned in the documentation and that's a big hole. A little example to play a bit: #include <boost/move_semantics/move.hpp> #include "movable.hpp" //Catch by value void function(movable m) {} //Catch by reference void function_ref(const movable &m) {} //Catch by reference void function_ref(BOOST_RV_REF(movable) m) {} int main() { movable m; movable cm; //move returns rv ref BOOST_RV_REF(movable) r = boost::move(m); //Conversion operator applied BOOST_RV_REF(movable) q = movable(); //Dangerous for a container if const overload is disabled BOOST_RV_REF(movable) s = m; //Catch by value, ok m = movable(); //Does not compile //function(m); //Compiles function(movable()); //Does not compile in C++03 //function_ref(movable()); //Compiles function_ref(boost::move(m)); return 0; } Regards, Ion

Hi, ----- Original Message ----- From: "Ion Gaztañaga" <igaztanaga@gmail.com> To: <boost@lists.boost.org> Sent: Tuesday, February 17, 2009 11:00 PM Subject: [boost] [move] Library uploaded to sandbox
Hi to all,
<snip>
I think this needs a clarification. The MoveEmulation library do not depends neither on Boost.Interprocess not on Boost.Intrusive. Isnt't it? <snip>
I appreciate the good work you have done. Thanks Ion.
Now that you have already tested with your InterProcess and Intrusive containers I'll adapt my own libraries to use it and see how it works.
I completly agree. What about requesting a formal review? Thanks again, Vicente

vicente.botet wrote:
No, there are no dependencies, but if you have a back_move_inserter, you need a container that has move-capabilities. I adapted Interprocess ones to test the Move library.
I completly agree. What about requesting a formal review?
If there is some consensus, no problem. But I really want to avoid long and time-consuming review (and boost reviews require a very big effort, just see the ratio of announced/accepted libraries ;-) ), because my time is quite limited right now. That's why I wanted to get some serious feedback. Regards, Ion

----- Original Message ----- From: "Ion Gaztañaga" <igaztanaga@gmail.com> To: <boost@lists.boost.org> Sent: Tuesday, February 17, 2009 11:00 PM Subject: [boost] [move] Library uploaded to sandbox
<snip>
Hi, The test for the move library and the intrusive constainers pass on gcc-3.4.4 under cygwin, but I have some trouble chile compiling interprocess. I had no problems while compiling the 1.38.0. It seems that the fact to declare the variable m_nOwner interprocess_recursive_mutex.hpp volatile break on this compiler. volatile detail::OS_systemwide_thread_id_t m_nOwner; On 1.38.0 detail::OS_systemwide_thread_id_t m_nOwner; detail::OS_systemwide_thread_id_t th_id = detail::get_current_systemwide_thread_id(); 43 if(detail::equal_systemwide_thread_id(th_id, m_nOwner)){ The move semantincs one volatile detail::OS_systemwide_thread_id_t m_nOwner; const detail::OS_systemwide_thread_id_t thr_id = detail::get_current_systemwide_thread_id(); 42 const detail::OS_systemwide_thread_id_t old_id = m_nOwner; if(detail::equal_systemwide_thread_id(thr_id , old_id)){ Any ideas? Best, Vicente _______________ gcc.compile.c++ ../../../bin.v2/libs/interprocess/test/flat_tree_test.test/gcc-3.4.4/debug/threading-multi/flat_tree_test.o "g++" -ftemplate-depth-128 -O0 -fno-inline -Wall -g -mthreads -DBOOST_ALL_NO_LIB=1 -DBOOST_THREAD_POSIX -DBOOST_THREAD_USE_LIB=1 -I"../../.." -I"/home/Vicente/boost/boost_1_38_0" -I"/home/Vicente/boost/sandbox/boost.move_semantics" -c -o "C:\cygwin\home\Vicente\boost\sandbox\boost.move_semantics\bin.v2\libs\interprocess\test\flat_tree_test.test\gcc-3.4.4\debug\threading-multi\flat_tree_test.o" "flat_tree_test.cpp" In file included from ../../../boost/interprocess/sync/interprocess_recursive_mutex.hpp:122, from ../../../boost/interprocess/sync/mutex_family.hpp:22, from ../../../boost/interprocess/detail/managed_memory_impl.hpp:23, from ../../../boost/interprocess/managed_shared_memory.hpp:21, from flat_tree_test.cpp:13: ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp: In member function `void boost::interprocess::interprocess_recursive_mutex::lock()': ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:43: error: no matching function for call to `boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(volatile boost::interprocess::detail::OS_systemwide_thread_id_t&)' ../../../boost/interprocess/detail/os_thread_functions.hpp:81: note: candidates are: boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(const boost::interprocess::detail::OS_systemwide_thread_id_t&) ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:53: error: passing `volatile boost::interprocess::detail::OS_systemwide_thread_id_t' as `this' argument of `boost::interprocess::detail::OS_systemwide_thread_id_t& boost::interprocess::detail::OS_systemwide_thread_id_t::operator=(const boost::interprocess::detail::OS_systemwide_thread_id_t&)' discards qualifiers ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp: In member function `bool boost::interprocess::interprocess_recursive_mutex::try_lock()': ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:61: error: no matching function for call to `boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(volatile boost::interprocess::detail::OS_systemwide_thread_id_t&)' ../../../boost/interprocess/detail/os_thread_functions.hpp:81: note: candidates are: boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(const boost::interprocess::detail::OS_systemwide_thread_id_t&) ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:71: error: passing `volatile boost::interprocess::detail::OS_systemwide_thread_id_t' as `this' argument of `boost::interprocess::detail::OS_systemwide_thread_id_t& boost::interprocess::detail::OS_systemwide_thread_id_t::operator=(const boost::interprocess::detail::OS_systemwide_thread_id_t&)' discards qualifiers ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp: In member function `bool boost::interprocess::interprocess_recursive_mutex::timed_lock(const boost::posix_time::ptime&)': ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:85: error: no matching function for call to `boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(volatile boost::interprocess::detail::OS_systemwide_thread_id_t&)' ../../../boost/interprocess/detail/os_thread_functions.hpp:81: note: candidates are: boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(const boost::interprocess::detail::OS_systemwide_thread_id_t&) ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:95: error: passing `volatile boost::interprocess::detail::OS_systemwide_thread_id_t' as `this' argument of `boost::interprocess::detail::OS_systemwide_thread_id_t& boost::interprocess::detail::OS_systemwide_thread_id_t::operator=(const boost::interprocess::detail::OS_systemwide_thread_id_t&)' discards qualifiers ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp: In member function `void boost::interprocess::interprocess_recursive_mutex::unlock()': ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:104: error: no matching function for call to `boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(volatile boost::interprocess::detail::OS_systemwide_thread_id_t&)' ../../../boost/interprocess/detail/os_thread_functions.hpp:81: note: candidates are: boost::interprocess::detail::OS_systemwide_thread_id_t::OS_systemwide_thread_id_t(const boost::interprocess::detail::OS_systemwide_thread_id_t&) ../../../boost/interprocess/sync/emulation/interprocess_recursive_mutex.hpp:110: error: passing `volatile boost::interprocess::detail::OS_systemwide_thread_id_t' as `this' argument of `boost::interprocess::detail::OS_systemwide_thread_id_t& boost::interprocess::detail::OS_systemwide_thread_id_t::operator=(const boost::interprocess::detail::OS_systemwide_thread_id_t&)' discards qualifiers ...failed gcc.compile.c++ ../../../bin.v2/libs/interprocess/test/flat_tree_test.test/gcc-3.4.4/debug/threading-multi/flat_tree_test.o... ...failed updating 1 target...

on Tue Feb 17 2009, Ion Gaztañaga <igaztanaga-AT-gmail.com> wrote:
Wow, this is way cool: you've found a way to allow the default copy ctor and assignment operators to be in place, and yet still treat rvalues specially! I guess that's because overloading prefers derived classes: template <class B> struct D : B {}; template <class T> struct B { operator D<B>&() { return *static_cast<D<B>* >(this); } B() {} B(B const&) // move ctor { T::copy_ctor_called(); } B(D<B>& x) // move ctor { } }; B<int> f() { return B<int>(); } // <== most likely elided; otherwise move B<int> x(f()); // <== calls move ctor B<int> y(x); // <== calls copy ctor, generating error So you're relying on a wee bit of undefined behavior by downcasting your B&, but that's alright with me. The one thing I guess you give up when doing things this way is the ultimate efficiency of copy elision for incoming parameters. However, we can tell people that when they're going to copy the rhs anyway, they should pass by value. That means self& operator=(self rhs) { swap(*this,rhs); return *this; } should still be the canonical assignment operator (if your docs can rely on universally-benign undefined behavior, surely they can also rely on universally-implemented copy elision). Hmm, and does this work? template <class T> struct C : B<T> { operator D<C>&(); C(D<C>& rhs); C(); }; int g(B<int> const&); int test = g(C<int>()); Yes! Pretty slick.
Oh, yeah, you definitely should. I think Howard has a move semantics test suite we can throw at this library. Howard?
Jah; those'll come in time.
I like this, very very much. It's so clean and obvious that it even worries me a little: didn't I try and discard this approach once? I dunno, but if we can get it to pass a rigorous test suite, I think it's totally awesome. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Interesting! I'll have to play with this - One issue that thwarted a lot of attempts at a better move library were classes that use type erasure. For example - the explicit constructors for adobe::any_regular_t (similar to boost any) look like this: template <typename T> explicit any_regular_t(const T& x, typename copy_sink<T>::type = 0) { ::new (storage()) typename traits<T>::model_type(x); } template <typename T> explicit any_regular_t(T x, typename move_sink<T>::type = 0) { ::new (storage()) typename traits<T>::model_type(move(x)); } The move_sink and copy_sink distinguish between movable and non- movable types. There were several solutions that relied on wrapper types that failed because T would be deduced as the wrapper type - I have no idea if that's an issue here but thought I'd point out the issue. If you're looking for a large test case you might try replacing the move library for ASL and see what happens - we have many test cases that verify move is working correctly. Sean On Feb 18, 2009, at 9:11 AM, David Abrahams wrote:

On Feb 18, 2009, at 12:11 PM, David Abrahams wrote:
Oh, yeah, you definitely should. I think Howard has a move semantics test suite we can throw at this library. Howard?
You could start with the tests in unique_ptr.zip found here: http://home.roadrunner.com/~hinnant/unique_ptr03.html This is likely not a complete test suite, and it concentrates on unique_ptr. I also haven't reviewed it lately to take into account the recommendations of N2831 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2831.html ). -Howard

"David Abrahams" <dave@boostpro.com> wrote in message news:87fxib8ybh.fsf@mcbain.luannocracy.com...> Wow, this is way cool: you've found a way to allow the default> copy ctor and assignment operators to be in place, and yet still treat> rvalues specially! I guess that's because overloading prefers derived> classes: No. this is because of return value optimization in which the temporary is constructed directly into destination and therefore the copy ctor is not called (hence its definition is not instantiated in your case). This is common frontend optimization but it might be fragile assumption. Try removing the "move-enabling" members or put the copy ctor as private to see. The "move-enabling" members are only effective for the explicit move (via move(lvalue)) so they are essential after all. > template <class B>> struct D : B> {};>> template <class T>> struct B {> operator D<B>&() { return *static_cast<D<B>* >(this); }>> B() {}>> B(B const&) // move ctor> { T::copy_ctor_called(); }>> B(D<B>& x) // move ctor> { }>> };>> B<int> f() { return B<int>(); } // <== most likely elided; otherwise > move> B<int> x(f()); // <== calls move ctor> B<int> y(x); // <== calls copy ctor, generating error Rani

on Sat Feb 21 2009, "Rani Sharoni" <rani_sharoni-AT-hotmail.com> wrote:
No.
Since it turns out I am the inventor of this technique, I'd like to see why you think I don't understand it :-)
Argjjh, you're right. So in this respect it's almost identical to the Adobe approach. Are there any substantial differences?
The "move-enabling" members are only effective for the explicit move (via move(lvalue)) so they are essential after all.
I wasn't trying to say the move-enabling members were inessential... but even if I was saying that, I'm afraid I don't understand what you mean. Rani -- Dave Abrahams BoostPro Computing http://www.boostpro.com

"David Abrahams" <dave@boostpro.com> wrote in message news:m23ae6e634.fsf@boostpro.com...
I was just commenting about your explenation and not your understanding about the application.
I don't know much about the Adobe approach but AFAICT, given a viable copy ctor, both should work even when the frontend optimization doesn't take place.
I was commeting about the move-enabling members in general and such are needed if move from lvalue is required. OTOH, the move-enabling members can be implemented in other ways since they are actually not related at all to the rvalue case. Rani

No. this is because of return value optimization in which the temporary is constructed directly into destination and therefore the copy ctor is not called (hence its definition is not instantiated in your case). This is common frontend optimization but it might be fragile assumption. Try removing the "move-enabling" members or put the copy ctor as private to see. The "move-enabling" members are only effective for the explicit move (via move(lvalue)) so they are essential after all. Rani BTW - sorry for the bad formatting in the previous post. I pasted it from the hotmail "subscription required" reply.

----- Original Message ----- From: "Ion Gaztañaga" <igaztanaga@gmail.com> To: <boost@lists.boost.org> Sent: Tuesday, February 17, 2009 11:00 PM Subject: [boost] [move] Library uploaded to sandbox
<snip>
Hi, I was wondering if we can define a implicit conversion from rv<Derived>& to rv<Base>& if is_convertible<Derived,Base> template <typename U> typename enable_if<move_detail::is_convertible<T,U>, rv<U>&>::type convert_to() { return (static_cast<rv<U>& >(static_cast<U&>(*this))); } template <typename U> operator rv<U>&() { convert_to<U>(); } With this implicit conversion the Derived(BOOST_RV_REF(Derived) x) // Move ctor : Base(boost::move(static_cast<Base&>(x))), mem_(boost::move(x.mem_)) { } could be Derived(BOOST_RV_REF(Derived) x) // Move ctor : Base(x), mem_(boost::move(x.mem_)) { } What do you think? Vicente

----- Original Message ----- From: "Mathias Gaunard" <mathias.gaunard@ens-lyon.org> To: <boost@lists.boost.org> Sent: Saturday, February 21, 2009 9:28 PM Subject: Re: [boost] [move] Library uploaded to sandbox
Do you mean that Derived&& is not convertible to Base&&? Vicente

on Sat Feb 21 2009, Mathias Gaunard <mathias.gaunard-AT-ens-lyon.org> wrote:
Rvalue references with a name become lvalues references, I think.
Correct. Or rather, in expressions they are lvalues. -- Dave Abrahams BoostPro Computing http://www.boostpro.com

Hi Ion: I've been playing with this code a bit lately, on some antique (pre-SFINAE) compilers. I've sent you private emails but may as well post to the list to share with everyone else, and also this has become a bit clearer to me. SunPro Studio 8: The implementation of "operator rv<T>&() { return static_cast<rv<T>&>(*this); }" produces an infinite loop. Replacing "static_cast" by "reinterpret_cast" solved the problem. AIX xlC 8: I've run into the problem of catch-by-reference. In the mailing, you said earlier on the mailing list:
But when push_back instead is a constructor that takes a movable class T, as in: struct U : T { U(const T& x) : T(x) {} U(rv<T>& x) : T(x) {} }; xlC did not select the first overload, rather I obtained an ambiguity when trying to create U u(T(...)); because the compiler had the two conversion sequences: 1. T user-conversion to rv<T>& then using second ctor. 2. T to const T& using lvalue-to-rvalue conversion, then user conversion to U using first ctor, then using the implicit copy ctor. So the ambiguity is between second ctor and implicit copy ctor, while the first ctor still plays a role. I don't think this is correct behavior, though, and g++ does not complain about ambiguity. Any explanation welcome. Besides those two kinks, I found the whole thread enlightening. Thanks! Cheers, -- Hervé Brönnimann hervebronnimann@mac.com PS: As promised, I attach the patched move.hpp with the#ifndef BOOST_NO_SFINAE #else #endif branch implemented. Testing minimal, but at least compiled your test example (which you offered as "A little example to play a bit: ...") . On Feb 17, 2009, at 5:00 PM, Ion Gaztañaga wrote:

Hervé Brönnimann wrote:
Ok, thanks.
Ok, thanks, I want to find a bit of time to do a new release next week. I'm separating interprocess containers and placing them in a boost::container namespace (boost/container folder) so we have a some standard containers to keep playing ;-) Best, Ion
participants (11)
-
Beman Dawes
-
Christian Holmquist
-
David Abrahams
-
Hervé Brönnimann
-
Howard Hinnant
-
Ion Gaztañaga
-
Mathias Gaunard
-
Olaf Peter
-
Rani Sharoni
-
Sean Parent
-
vicente.botet