#include #include #include // rv& emulates T&& template< class T > class rv : public T { rv(); rv(rv const &); rv& operator=(rv const &); }; template< class T > struct has_move_emulation : boost::is_convertible< T, rv& > { }; // *** NEW EMULATED RVALUE REFERENCE *** // generic_rv< F, Result > also emulates an rvalue reference, but in a kind of // type-erased way. The actual object referred to is referenced by a void // pointer. To be able to cast the void pointer back to a pointer-to-object, we // need to package the void pointer together with some kind of dispatching // mechanism. We use a function reference to an instantiation of // cast_forward. template< class F, class Result = void > struct generic_rv { typedef Result (&cast_forward_type)(F, void*); generic_rv(cast_forward_type cast_forward, void* p) : m_cast_forward(cast_forward), m_p(p) { } Result cast_forward(F f) const { return m_cast_forward(f, m_p); } template< class T > static Result cast_forward(F f, void* const p) { return f(static_cast< rv& >(*static_cast< T* >(p))); } private: cast_forward_type m_cast_forward; void* m_p; }; // X is just a typical move-emulation-enabled class. struct X { X() { } X(X const &) { } X(rv&) { } X& operator=(X) { return *this; } X& operator=(rv&) { return *this; } operator rv&() { return *static_cast< rv* >(this); } operator rv const &() const { return *static_cast< rv const * >(this); } // *** NEW CONVERSION OPERATOR *** // X provides an implicit conversion to generic_rv. template< class F, class Result > operator generic_rv< F, Result >() { return generic_rv< F, Result >( generic_rv< F, Result >::template cast_forward, static_cast< void* >(this) ); } }; struct some_fn { template< class T > void operator()(T&) const { std::cout << "some_fn::operator()(T&) const" << std::endl; } template< class T > typename boost::disable_if< has_move_emulation >::type operator()(T const &) const { std::cout << "some_fn::operator()(T const &) const" << std::endl; } // Notice that this overload requires template parameter deduction, hence // the compiler cannot apply an implicit conversion to rv& from rvalues // of move-emulation-enabled types. In other words, this overload can only // bind to *explicitly* created emulated rvalue references, not to "real" // rvalues :( template< class T > void operator()(rv&) const { std::cout << "some_fn::operator()(rv&) const" << std::endl; } // *** NEW FUNCTION OVERLOAD TO CAPTURE RVALUES *** // Since this overload requires no template parameter deduction, the // compiler *can* apply an implicit conversion to generic_rv<...> from // rvalues of move-emulation-enabled types. Yes, there *may* be some // runtime overhead from the indirect dispatch, but that will often be // preferable to copying x! void operator()(generic_rv< some_fn > const x) const { return x.cast_forward(*this); } }; template< class T > T make() { return T(); } int main(int argc, char* argv[]) { int a = 0; int const b = 0; some_fn()(a); // some_fn::operator()(T&) const some_fn()(b); // some_fn::operator()(T const &) const some_fn()(make< int >()); // some_fn::operator()(T const &) const X x; X const y; some_fn()(x); // some_fn::operator()(T&) const some_fn()(y); // some_fn::operator()(T&) const some_fn()(make()); // some_fn::operator()(rv&) const some_fn()(static_cast< rv& >(make())); // some_fn::operator()(rv&) const return 0; }