In order to make our optional regular, we need to provide an
implementation of the Less-Than operator <. For two optionals with a value, it makes sense to employ their < operator.
Also we already defined that two empty optionals are
considered to be equal. Therefore we only need to decide, how an optional with a value shall compare to an optional
without a value. std::optional considers an optional without a value to be
less than an optional without a value.
So our rules for the < operator are:
Given two instances a and b of an optional, a is less than b if and only
if a has no value and b has a value.
if both have values and the value of a is less than the value of b.
We can now derive test cases for these two cases.
We need to provide an implementation for the < operator now. Just as it was the case for the == operator, we could
implement it as a member function, but we will implement it as a friend function for similar reasons like we did it for
the == operator.
This implementation will – similarly as out first implementation of the
== operator
– obviously make our tests pass but it is obviously wrong. Again, we need to implement a few tests for the negative
cases. We could obviously write them down one by one, but we can also reuse our existing test cases: if two optionals are
equal, one can never be less than the other. So we will just extend the existing test cases with checks for the <
operator.
Now our tests are failing, so we need to provide a proper implementation.
All our tests are now passing again.
If we now have a second look at our test cases, we may see that there is some redundancy:
the negative test cases for the == operator and the positive test cases for the < operator can be merged.
It seems reasonable to add the checks for the == operator to the tests cases for the < operator.
The Other Comparison Operators
==, != and < are not the only comparison operators in C++, there are also <=, > and >=.
Although they are not required for a regular type, it makes still sense to implement them, as users will usually assume,
that all of them are available if one of them is available.
Thankfully, we can implement all of them in terms of of the < operator and also reuse our existing test cases.
Based on these tests, we can now implement the missing operators <=, > and >= by delegating – directly or
indirectly – to <.
Conclusion
All comparison operators are now implemented for our optional. Especially the < operator finally permits use cases like
sorting a vector of optionals
or using an optional as the key of a std::map.
In an upcoming post, we will have a look at the remaining operations in order to make sure that our optional is
regular.