
On Mon, Jan 23, 2012 at 10:16 AM, Vicente J. Botet Escriba < vicente.botet@wanadoo.fr> wrote:
Le 23/01/12 17:55, Jeffrey Lee Hellrung, Jr. a écrit :
On Sat, Jan 21, 2012 at 4:22 PM, Vicente Botet<vicente.botet@wanadoo.fr**
wrote:
Hi,
Are there any news about this Move improvements?
Best, Vicente
None from my end.
I've thought about it a bit since, and I *think* you can get by using this with any change to the existing Boost.Move infrastructure (only additions), so, if desired, it could be added to an "advanced techniques in C++03" section or something like that.
Do you think it's worth adding to Boost.Move?
I need to emulate the thread constructor
template <class F, class ...Args> explicit thread(F&& f, Args&&... args);
at least for 2 args.
If I have understood, there are some constraints when applying your technique on constructors, but guess that this is better than nothing.
So yes, I would like to see a clear description on how to emulate this kind of functions with Boost.Move+ your additions
Apologies for the long delay. I finally got a minimal example program out to illustrate the idea. ---------------- #include <iostream> #include <typeinfo> #include <boost/move/move.hpp> #include <boost/mpl/always.hpp> #include <boost/mpl/and.hpp> #include <boost/mpl/apply.hpp> #include <boost/type_traits/integral_constant.hpp> #include <boost/type_traits/is_const.hpp> #include <boost/utility/addressof.hpp> #include <boost/utility/enable_if.hpp> namespace { // Necessary to workaround an MSVC9 ICE. template< class Pred, class T, bool = boost::has_move_emulation_enabled<T>::value
struct rv_sink_enable_ctor; template< class Pred, class T> struct rv_sink_enable_ctor< Pred, T, false > { }; template< class Pred, class T> struct rv_sink_enable_ctor< Pred, T, true > : boost::enable_if_c< boost::mpl::apply1< Pred, T >::type::value > { }; template< class Visitor, class Result = void, class Pred = boost::mpl::always< boost::true_type >
struct rv_sink { typedef Result result_type; // implicit on purpose template< class T > rv_sink(T const & x, typename rv_sink_enable_ctor< Pred, T >::type* = 0) : m_apply(apply<T>), mp(static_cast< void* >(boost::addressof(const_cast< T& >(x)))) { } result_type operator()(Visitor visitor) const { return m_apply(visitor, mp); } private: template< class T > static result_type apply(Visitor visitor, void* p) { return visitor(boost::move(*static_cast< T* >(p))); } result_type (&m_apply)(Visitor, void*); void* const mp; }; struct A { private: struct ctor_rv_sink { struct binder { explicit binder(A& this_) : m_this(this_) { } typedef void result_type; template< class T > void operator()(T& x) const { return m_this.init(x); } private: A& m_this; }; typedef rv_sink< binder > type; }; public: // lvalues template< class T > explicit A(T& x) { init(x); } // movable rvalues explicit A(ctor_rv_sink::type const x) { x(ctor_rv_sink::binder(*this)); } // const lvalues + non-movable rvalues template< class T > explicit A(T const & x, typename boost::disable_if_c< boost::has_move_emulation_enabled<T>::value >::type* = 0) { init(x); } private: template< class T > void init(T&) { std::cout << "A::init(T&) with T = " << typeid( T ).name() << (boost::is_const<T>::value ? " (const)" : "") << std::endl; } }; struct X { X() { std::cout << "X::X()" << std::endl; } X(X const &) { std::cout << "X::X(X const &)" << std::endl; } X& operator=(X const &) { std::cout << "X::operator=(X const &)" << std::endl; return *this; } static X make() { return X(); } }; struct Y { BOOST_COPYABLE_AND_MOVABLE( Y ) public: Y() { std::cout << "Y::Y()" << std::endl; } Y(Y const &) { std::cout << "Y::Y(Y const &)" << std::endl; } Y(BOOST_RV_REF( Y )) { std::cout << "Y::Y(Y&&)" << std::endl; } Y& operator=(BOOST_COPY_ASSIGN_REF( Y )) { std::cout << "Y::operator=(Y const &)" << std::endl; return *this; } Y& operator=(BOOST_RV_REF( Y )) { std::cout << "Y::operator=(Y&&)" << std::endl; return *this; } static Y make() { return Y(); } }; } // namespace int main(int argc, char* argv[]) { std::cout << "Constructing x, cx, y, cy..." << std::endl; X x; X const cx; Y y; Y const cy; std::cout << "Constructing ax..." << std::endl; A ax(x); std::cout << "Constructing acx..." << std::endl; A acx(cx); std::cout << "Constructing arx..." << std::endl; A arx(X::make()); std::cout << "Constructing ay..." << std::endl; A ay(y); std::cout << "Constructing acy..." << std::endl; A acy(cy); std::cout << "Constructing ary..." << std::endl; A ary(Y::make()); return 0; } ---------------- (The print statements are just to verify expected behavior.) So, with a 1 argument constructor, you can catch rvalues of move-emulation-enabled types using the above technique. You could extend this to 2 or 3 arguments, but it looks like it would take some binding and overload acrobatics to cover all the possibilities. If this looks like an acceptable solution, I can help with adding the requisite boilerplate (maybe some Boost.PP magic can make this manageable) to Boost.Thread. Note: This isn't as slick, efficient, or easy-to-implement as Dan's solution, but it doesn't rely on non-standard behavior and, perhaps, is safer regarding volatile move-emulation-enabled types. - Jeff