#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 X#" << id << " <- X#" << 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 X#" << id << " <- X#" << rhs.id << " (const)" << std::endl; } ~X() { std::cout << "destroy X#" << 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 X#" << id << " <== X#" << 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 Y#" << id << " <- Y#" << 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 Y#" << id << " <- Y#" << rhs.id << " (const)" << std::endl; } ~Y() { std::cout << "destroy Y#" << 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 Y#" << id << " <== Y#" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int Y::cnt; struct V : virtual public X { static int cnt; // count the number of Vs V() : X() , id(++cnt) , owner(true) { std::cout << "V() #" << id << std::endl; } // non-const lvalue - copy ctor V(V& rhs) : X(rhs) , id(++cnt) , owner(true) { std::cout << "copy V#" << id << " <- V#" << rhs.id << std::endl; } // const lvalue - T will be deduced as V const template V(T& rhs, typename enable_if_same::type = 0) : X(static_cast(rhs) ) , id(++cnt) , owner(true) { std::cout << "copy V#" << id << " <- #V" << rhs.id << " (const)" << std::endl; } ~V() { std::cout << "destroy V#" << id << (owner?"":" (EMPTY)") << std::endl; } private: // Move stuff struct ref { ref(V*p) : p(p) {} V* p; }; public: // Move stuff operator ref() { return ref(this); } // non-const rvalue V(ref rhs) : X( X::ref(rhs.p) ) , id(++cnt) , owner(rhs.p->owner) { std::cout << "MOVE V#" << id << " <== V#" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int V::cnt; struct W : virtual public X { static int cnt; // count the number of Ws W() : X() , id(++cnt) , owner(true) { std::cout << "W() #" << id << std::endl; } // non-const lvalue - copy ctor W(W& rhs) : X(rhs) , id(++cnt) , owner(true) { std::cout << "copy W#" << id << " <- W#" << rhs.id << std::endl; } // const lvalue - T will be deduced as W const template W(T& rhs, typename enable_if_same::type = 0) : X(static_cast(rhs) ) , id(++cnt) , owner(true) { std::cout << "copy W#" << id << " <- W#" << rhs.id << " (const)" << std::endl; } ~W() { std::cout << "destroy W#" << id << (owner?"":" (EMPTY)") << std::endl; } private: // Move stuff struct ref { ref(W*p) : p(p) {} W* p; }; public: // Move stuff operator ref() { return ref(this); } // non-const rvalue W(ref rhs) : X( X::ref(rhs.p) ) , id(++cnt) , owner(rhs.p->owner) { std::cout << "MOVE W#" << id << " <== W#" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int W::cnt; struct U : virtual public V, virtual public W { static int cnt; // count the number of Us U() : X() , V() , W() , id(++cnt) , owner(true) { std::cout << "U() #" << id << std::endl; } // non-const lvalue - copy ctor U(U& rhs) : X(rhs) , V(rhs) , W(rhs) , id(++cnt) , owner(true) { std::cout << "copy U#" << id << " <- U#" << rhs.id << std::endl; } // const lvalue - T will be deduced as U const template U(T& rhs, typename enable_if_same::type = 0) : X(static_cast(rhs) ) , V(static_cast(rhs) ) , W(static_cast(rhs) ) , id(++cnt) , owner(true) { std::cout << "copy U#" << id << " <- U#" << rhs.id << " (const)" << std::endl; } ~U() { std::cout << "destroy U#" << id << (owner?"":" (EMPTY)") << std::endl; } private: // Move stuff struct ref { ref(U*p) : p(p) {} U* p; }; public: // Move stuff operator ref() { return ref(this); } // non-const rvalue U(ref rhs) : X( X::ref(rhs.p) ) , V( V::ref(rhs.p) ) , W( W::ref(rhs.p) ) , id(++cnt) , owner(rhs.p->owner) { std::cout << "MOVE U#" << id << " <== U#" << rhs.p->id << std::endl; rhs.p->owner = false; assert(owner); } private: // Data members int id; bool owner; }; int U::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; } U sourceU() { return U(); } U const csourceU() { return U(); } void sinkU(U) { std::cout << "in rvalue sinkU" << std::endl; } void sink2U(U&) { std::cout << "in non-const lvalue sink2U" << std::endl; } void sink2U(U const&) { std::cout << "in const lvalue sink2U" << std::endl; } void sink3U(U&) { std::cout << "in non-const lvalue sink3U" << 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; } { std::cout << "============================================" << std::endl; std::cout << " ------ test 38, direct init from rvalue ------- " << std::endl; #ifdef __GNUC__ // GCC having trouble parsing the extra parens U uz2((0, U() )); #else U uz2((U())); #endif std::cout << " ------ test 39, copy init from rvalue ------- " << std::endl; U uz4 = U(); std::cout << " ------ test 40, copy init from lvalue ------- " << std::endl; U uz5 = uz4; std::cout << " ------ test 41, direct init from lvalue ------- " << std::endl; U uz6(uz4); std::cout << " ------ test 42, construct const ------- " << std::endl; U const uz7; std::cout << " ------ test 43, copy init from lvalue ------- " << std::endl; U uz8 = uz7; std::cout << " ------ test 44, direct init from lvalue ------- " << std::endl; U uz9(uz7); std::cout << " ------ test 45, pass rvalue by-value ------- " << std::endl; sinkU(sourceU()); std::cout << " ------ test 46, pass const rvalue by-value ------- " << std::endl; sinkU(csourceU()); std::cout << " ------ test 47, 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. sink2U(sourceU()); std::cout << " ------ test 48, pass const rvalue by overloaded reference ------- " << std::endl; sink2U(csourceU()); #if 0 // These two correctly fail to compile, just as desired std::cout << " ------ test 49, pass rvalue by non-const reference ------- " << std::endl; sink3U(sourceU()); std::cout << " ------ test 50, pass const rvalue by non-const reference ------- " << std::endl; sink3U(csourceU()); #endif std::cout << " ------ test 51, pass lvalue by-value ------- " << std::endl; sinkU(uz5); std::cout << " ------ test 52, pass const lvalue by-value ------- " << std::endl; sinkU(uz7); std::cout << " ------ test 53, pass lvalue by-reference ------- " << std::endl; sink2U(uz4); std::cout << " ------ test 54, pass const lvalue by const reference ------- " << std::endl; sink2U(uz7); #if 0 // correctly fails to compile, just as desired std::cout << " ------ test 55, pass const lvalue by-reference ------- " << std::endl; sink3U(uz7); #endif std::cout << " ------ test 56, pass rvalue by value to template param ------- " << std::endl; tsink(sourceU()); std::cout << "After this line is all compiler auto deletes" << std::endl; std::cout << "--------------------------------------------" << std::endl; } }