09 - user defined convertions
It's possible to define custom convertions by overloading operator T. The operator must be a member function that takes 0 arguments.
By default, the convertion is implicit. Since C++11 explicit can be used to disallow implicit convertions - using it is strongly recommended.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
// all code inside fraction class explicit operator float() const { return static_cast<float>(numerator()) / denominator(); } explicit operator double() const { return static_cast<double>(numerator()) / denominator(); } explicit operator long double() const { return static_cast<long double>(numerator()) / denominator(); } explicit operator bool() const { return numerator() != 0; } // not needed in C++11 and later bool operator!() const { return !operator bool(); } |
operator! must be a member function that takes 0 arguments. It has no restrictions on the return type although there is very little point in a type different than bool. Since C++11 ! performs contextual convertion to bool so overloading operator bool is enough - expressions like if (!obj) where ! is not overloaded will be treated as if (!static_cast<bool>(obj)).
Example usage:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
void fd(double); void fb(bool); fraction fr(1, 2); double d1 = fr; // error if "explicit" is used double d2 = static_cast<double>(fr); // ok fd(fr); // error if "explicit" is used fd(static_cast<double>(fr)); // ok bool is_non_zero1 = fr; // error if "explicit" is used bool is_non_zero2 = static_cast<bool>(fr); // ok fb(fr); // error if "explicit" is used fb(static_cast<bool>(fr)); // ok // always ok, "if" acts as an explicit convertion to bool if (fr) {} // C++ <= 98: ok even if only operator bool is overloaded (convertion is implicit) // C++ >= 11: ok even if only explicit operator bool is overloaded (! applies contextual convertion) if (!fr) {} |
Trivia
The explicit convertion feature has been added after it has been realized that user-defined implicit convertions are hardly ever useful. Expressions like if (a == b) where a and b are objects of different types would compile - the compiler would implicitly convert both objects to bool and then compare them.
To solve this (in era before C++11), there was a safe bool idiom. A class did not overload convertion to bool, but to a member function pointer or a member data pointer, which themselves are convertible to bool. Then it added some template overloads of operator== and operator!= which call empty member function to cause compilation errors on specific (unwanted) comparisons. In short, it was a pretty complex idiom to implement correctly, only to prevent certain unwanted implicit convertions to bool.
After C++11 introduced explicit for user-defined convertions, the safe bool idiom is now obsolete.
Recommendation
Make user-defined convertions explicit, especially convertions to bool.