#include #include template struct enable_if_same { }; template struct enable_if_same { typedef char type; }; struct X { static int cnt; // count the number of Xs X() : id(++cnt) , owner(true) { std::cout << "X() #" << id << std::endl; } // non-const lvalue - copy ctor X(X& rhs) : id(++cnt) , owner(true) { std::cout << "copy #" << id << " <- #" << rhs.id << std::endl; } // const lvalue - T will be deduced as X const template X(T& rhs, typename enable_if_same::type = 0) : id(++cnt) , owner(true) { std::cout << "copy #" << id << " <- #" << rhs.id << " (const)" << std::endl; } ~X() { std::cout << "destroy #" << id << (owner?"":" (EMPTY)") << std::endl; } private: // Move stuff struct ref { ref(X*p) : p(p) {} X* p; }; public: // Move stuff operator ref() { return ref(this); } // non-const rvalue X(ref rhs) : id(++cnt) , owner(rhs.p->owner) { std::cout << "MOVE #" << id << " <== #" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int X::cnt; struct Y : public X { static int cnt; // count the number of Ys Y() : X() , id(++cnt) , owner(true) { std::cout << "Y() #" << id << std::endl; } // non-const lvalue - copy ctor Y(Y& rhs) : X(rhs) , id(++cnt) , owner(true) { std::cout << "copy #" << id << " <- #" << rhs.id << std::endl; } // const lvalue - T will be deduced as Y const template Y(T& rhs, typename enable_if_same::type = 0) : X(static_cast(rhs) ) , id(++cnt) , owner(true) { std::cout << "copy #" << id << " <- #" << rhs.id << " (const)" << std::endl; } ~Y() { std::cout << "destroy #" << id << (owner?"":" (EMPTY)") << std::endl; } private: // Move stuff struct ref { ref(Y*p) : p(p) {} Y* p; }; public: // Move stuff operator ref() { return ref(this); } // non-const rvalue Y(ref rhs) : X( X::ref(rhs.p) ) , id(++cnt) , owner(rhs.p->owner) { std::cout << "MOVE #" << id << " <== #" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int Y::cnt; X source() { return X(); } X const csource() { return X(); } void sink(X) { std::cout << "in rvalue sink" << std::endl; } void sink2(X&) { std::cout << "in non-const lvalue sink2" << std::endl; } void sink2(X const&) { std::cout << "in const lvalue sink2" << std::endl; } void sink3(X&) { std::cout << "in non-const lvalue sink3" << std::endl; } template void tsink(T) { std::cout << "in templated rvalue sink" << std::endl; } Y sourceY() { return Y(); } Y const csourceY() { return Y(); } void sinkY(Y) { std::cout << "in rvalue sinkY" << std::endl; } void sink2Y(Y&) { std::cout << "in non-const lvalue sink2Y" << std::endl; } void sink2Y(Y const&) { std::cout << "in const lvalue sink2Y" << std::endl; } void sink3Y(Y&) { std::cout << "in non-const lvalue sink3Y" << std::endl; } int main() { { std::cout << " ------ test 1, direct init from rvalue ------- " << std::endl; #ifdef __GNUC__ // GCC having trouble parsing the extra parens X z2((0, X() )); #else X z2((X())); #endif std::cout << " ------ test 2, copy init from rvalue ------- " << std::endl; X z4 = X(); std::cout << " ------ test 3, copy init from lvalue ------- " << std::endl; X z5 = z4; std::cout << " ------ test 4, direct init from lvalue ------- " << std::endl; X z6(z4); std::cout << " ------ test 5, construct const ------- " << std::endl; X const z7; std::cout << " ------ test 6, copy init from lvalue ------- " << std::endl; X z8 = z7; std::cout << " ------ test 7, direct init from lvalue ------- " << std::endl; X z9(z7); std::cout << " ------ test 8, pass rvalue by-value ------- " << std::endl; sink(source()); std::cout << " ------ test 9, pass const rvalue by-value ------- " << std::endl; sink(csource()); std::cout << " ------ test 10, pass rvalue by overloaded reference ------- " << std::endl; // This one fails in Comeau's strict mode due to 12.2/1. GCC 3.3.1 passes it erroneously. sink2(source()); std::cout << " ------ test 11, pass const rvalue by overloaded reference ------- " << std::endl; sink2(csource()); #if 0 // These two correctly fail to compile, just as desired std::cout << " ------ test 12, pass rvalue by non-const reference ------- " << std::endl; sink3(source()); std::cout << " ------ test 13, pass const rvalue by non-const reference ------- " << std::endl; sink3(csource()); #endif std::cout << " ------ test 14, pass lvalue by-value ------- " << std::endl; sink(z5); std::cout << " ------ test 15, pass const lvalue by-value ------- " << std::endl; sink(z7); std::cout << " ------ test 16, pass lvalue by-reference ------- " << std::endl; sink2(z4); std::cout << " ------ test 17, pass const lvalue by const reference ------- " << std::endl; sink2(z7); #if 0 // correctly fails to compile, just as desired std::cout << " ------ test 18, pass const lvalue by-reference ------- " << std::endl; sink3(z7); #endif std::cout << " ------ test 19, pass rvalue by value to template param ------- " << std::endl; tsink(source()); std::cout << "After this line is all compiler auto deletes" << std::endl; std::cout << "--------------------------------------------" << std::endl; } { std::cout << "============================================" << std::endl; std::cout << " ------ test 20, direct init from rvalue ------- " << std::endl; #ifdef __GNUC__ // GCC having trouble parsing the extra parens Y yz2((0, Y() )); #else Y yz2((Y())); #endif std::cout << " ------ test 21, copy init from rvalue ------- " << std::endl; Y yz4 = Y(); std::cout << " ------ test 22, copy init from lvalue ------- " << std::endl; Y yz5 = yz4; std::cout << " ------ test 23, direct init from lvalue ------- " << std::endl; Y yz6(yz4); std::cout << " ------ test 24, construct const ------- " << std::endl; Y const yz7; std::cout << " ------ test 25, copy init from lvalue ------- " << std::endl; Y yz8 = yz7; std::cout << " ------ test 26, direct init from lvalue ------- " << std::endl; Y yz9(yz7); std::cout << " ------ test 27, pass rvalue by-value ------- " << std::endl; sinkY(sourceY()); std::cout << " ------ test 28, pass const rvalue by-value ------- " << std::endl; sinkY(csourceY()); std::cout << " ------ test 29, pass rvalue by overloaded reference ------- " << std::endl; // This one fails in Comeau's strict mode due to 12.2/1. GCC 3.3.1 passes it erroneously. sink2Y(sourceY()); std::cout << " ------ test 30, pass const rvalue by overloaded reference ------- " << std::endl; sink2Y(csourceY()); #if 0 // These two correctly fail to compile, just as desired std::cout << " ------ test 31, pass rvalue by non-const reference ------- " << std::endl; sink3Y(sourceY()); std::cout << " ------ test 32, pass const rvalue by non-const reference ------- " << std::endl; sink3Y(csourceY()); #endif std::cout << " ------ test 33, pass lvalue by-value ------- " << std::endl; sinkY(yz5); std::cout << " ------ test 34, pass const lvalue by-value ------- " << std::endl; sinkY(yz7); std::cout << " ------ test 35, pass lvalue by-reference ------- " << std::endl; sink2Y(yz4); std::cout << " ------ test 36, pass const lvalue by const reference ------- " << std::endl; sink2Y(yz7); #if 0 // correctly fails to compile, just as desired std::cout << " ------ test 36, pass const lvalue by-reference ------- " << std::endl; sink3Y(yz7); #endif std::cout << " ------ test 37, pass rvalue by value to template param ------- " << std::endl; tsink(sourceY()); std::cout << "After this line is all compiler auto deletes" << std::endl; std::cout << "--------------------------------------------" << std::endl; } }