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.