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; }
};
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
.
nullptr
. I couldn't think of anything other than that.nullptr
but allow 0
all yielded complicated schemes that didn't work. Basically, since there is no way to tell C++ you want a constexpr
function parameter, it is hard (I won't say impossible yet...) to devise a function that takes an int
argument, but results in compile time failure if the argument value is not 0
.nullptr
, then an easier implementation would be to use std::nullptr_t
directly rather than a separate safe_zero_idiom
class. (Admittedly, it is not as safe, since there is no way to access the safe_zero_idiom
type in your implementation.)struct X
{
int a;
friend bool operator<(const X& left, const X& right) { return left.a < right.a; }
friend bool operator<(const X& left, std::nullptr_t) { return left.a < 0; }
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With