/* * cloneable-strostrup.cc */ #include using namespace std; // // Every class having Has_Clone as a (private) base class must invoke // the Has_Clone default constructor, which does nothing but test // the constraint. If the constraint test fails the compilers will emit // an error message. // // Compiling with g++ and option -Wall will emit some warnings: // // warning: unused variable 'pc' // // Adding, in analogy with what's done in constraints() for 'test' // will only result in the same warning as for 'test', i.e. // "statement has no effect". // // warning: statement has no effect // // Refers to the expression statement 'test;', which will normally // will be optimized away. // template class Has_Clone { public: Has_Clone() { void (*p)() = constraints; } private: static void constraints() { T* (T::*test)() const = &T::clone; test; // supress some warnings } }; // // A test class C, having Has_Clone as a private base class, so // Has_Clone::constraints() will not add to the public interface // for C. // template class C : Has_Clone { public: C() {} private: }; // // Two test classes, one with a clone() function and one without: // template class Cloneable { public: Cloneable(); virtual ~Cloneable() {} virtual Cloneable* clone() const { return new Cloneable(*this); } }; template class Not_Cloneable { public: Not_Cloneable(); virtual ~Not_Cloneable() {} }; int main() { C< Cloneable > c; // error: `clone' is not a member of `Not_Cloneable' // C > nc; C< Cloneable >* pc = new C< Cloneable >; // error: `clone' is not a member of `Not_Cloneable' // C< Not_Cloneable >* pn = new C< Not_Cloneable >; delete pc; return 0; } template Cloneable::Cloneable() { cout << "Cloneable created" << endl; } template Not_Cloneable::Not_Cloneable() { cout << "Not_Cloneable created" << endl; }