With a very few exceptions (looking at you, Fahrenheit and Celsius temperature scales), units are linear, and the value zero is simultaneously the additive identity for all units at once.
So given
auto speed = dimensioned(20, _meter/_second);
auto power = dimensioned(75, _watt);
then
if (speed < 6) ...
if (power > 17) ...
makes no more sense than
if (speed > power) ...
you should write
if (speed < dimensioned(6, _mile/_hour)) ...
However, this DOES make sense:
if (speed < 0)
because 0 m/s == 0 mph == 0 A.U./fortnight or any other units that you care to use (for velocity). The question then is how to enable this and only this usage.
C++11 explicit operators and contextual conversion to bool
got rid of the need of the "safe-bool" idiom. It appears this problem can be solved with a comparable "safe-zero" idiom:
struct X
{
int a;
friend bool operator<(const X& left, const X& right) { return left.a < right.a; }
private:
struct safe_zero_idiom;
public:
friend bool operator<(const X& left, safe_zero_idiom*) { return left.a < 0; }
};
- Demo: http://ideone.com/vUxmxi
Unfortunately it seems that deployed dimension/unit libraries aren't doing this. (This question arose because I actually wanted to test whether a std::chrono::duration
was negative). Is this useful? Are there cases that would cause it to fail? Is there any easier way to permit comparison to zero?
One suspects that instead of implementing this for individual operators, there ought to exist an implicit conversion from literal zero to unit-tagged types.
I do note that it allows
X{1} < nullptr
as a valid expression :(, and unfortunately providing an inaccessible overload of type std::nullptr_t
doesn't fix this, since the Standard says in section 4.10
A null pointer constant of integral type can be converted to a prvalue of type
std::nullptr_t
.