Safe Bool Idiom
class BoolBase { public: operator bool() const { return true; } }; class A : public BoolBase {}; class B : public BoolBase {}; int main(int argc, char *argv[]) { if (A() == A()); // Ok. if (A() == B()); // Ok, but may NOT you want. return 0; }
Just look the code above, 'A() == B()' can compile, which is a potiential error.
All this error code is caused by the power of 'BoolBase::operator bool'. It will convert no matter the type of the object.
We must constraint the comparasion between different classes.
Solution:
template <typename T> class SafeBoolBase { public: void ToBool() const{} operator decltype(&SafeBoolBase::ToBool)() const { return &SafeBoolBase::ToBool; } // Replace common bool with a class address, // which can't convert automatically. }; class A : public SafeBoolBase<A> // Recursive template idiom. {}; class B : public SafeBoolBase<B> {}; int main(int argc, char *argv[]) { if (A() == A()); // Fine. if (A() == B()); // Compile error. return 0; }
We replace the type bool with address of specified class, which will NOT convert to each other automatically.
Recursive template idiom helps us makeing unique class ('class A' & 'class B') without writing new one. Because 'class A' is differenciated with 'class B', 'class SafeBoolBase<A>' will be different will 'class SafeBoolBase<B>'.