Consider the following struct:
struct Foo {
const Bar* x;
const Bar* y;
Foo(const Bar* _x, const Bar* _y = nullptr) : x(_x), y(_y) { assert(x); }
}
How do we define a strict weak ordering on x and y so that the object can be used within a std::set? Note that y can be a null pointer. As mentioned in Using std::less with nullptr the behavior of std::less on null pointers is undefined unspecified. Will the following solution be sufficient?
bool operator<(const Foo& rhs) const {
uintptr_t numX = reinterpret_cast<uintptr_t>(x);
uintptr_t numY = reinterpret_cast<uintptr_t>(y);
uintptr_t numRhsX = reinterpret_cast<uintptr_t>(rhs.x);
uintptr_t numRhsY = reinterpret_cast<uintptr_t>(rhs.y);
return std::tie(numX, numY) < std::tie(numRhsX, numRhsY);
}
EDIT: If not what is the proper way (e.g. how to combine std::less with std::tie)?
Using
std::less<Bar*>is sufficient (but usingoperator<is not). The pointer specializations ofstd::less(as the accepted answer to "Using std::less with nullptr" points out) guarantee a total ordering. Comparison withnullptris unspecified, meaning the standard does not impose a particular ordering, butstd::lessmust still produce a total ordering (and for a given pointerp,p < nullptrnecessarily produces the same value every time).Since a total ordering is stronger than a weak ordering, using
std::lessis sufficient in your case.There is no neat way, unfortunately. Since
std::tiereturns anstd::tuple, and comparison on tuples is defined in terms ofoperator<on their values (rather thanstd::less), you can't really usestd::tiehere. To usestd::less, you'd have to do it manually:As an aside, your current implementation (reinterpreting the pointers as integers) also produces a total ordering (obviously, since you're comparing integers) but instead of unspecified behavior you'll have implementation-defined behavior (from the
reinterpret_cast).