I am learning about std::strong_ordering
and std::weak_ordering
in C++20. According to the docs, std::strong_ordering
requires that equivalent values be indistinguishable, as opposed to std::weak_ordering
.
When researching std::weak_ordering
(especially in the context of the spaceship operator, <=>
), I generally encounter examples similar to the one below, which represents a multiplication expression:
// Represents a multiplication expression, the result of which is (multiplicand * multiplier)
struct Multiplication {
int multiplicand;
int multiplier;
};
This struct appears like it should be weakly ordered as different pairs of multiplicands and multipliers can evaluate to the same result, meaning equivalent values can be distinguishable (Multiplication{3, 2}
, Multiplication{6, 1}
, and Multiplication{1, 6}
all technically represent 6).
However, the trivial approach for comparing different Multiplication structs actually returns an std::strong_ordering
because multiplication results are ints and hence strongly ordered.
struct Multiplication {
int multiplicand;
int multiplier;
// This returns std::strong_ordering by default
auto operator<=>(Multiplication rhs) const
{
return (multiplicand * multiplier) <=> (rhs.multiplicand * rhs.multiplier);
}
};
Is it then my responsibility to explicitly annotate the return type as std::weak_ordering
in this case to make it semantically accurate?
According to the docs,
std::strong_ordering
requires that equivalent values be indistinguishable, as opposed tostd::weak_ordering
.
This is incorrect. It requires "substitutability", which in the standard is defined as:
the property that
f(a) == f(b)
is true whenevera == b
is true, wheref
denotes a function that reads only comparison-salient state that is accessible via the argument’s public const members.
That's a very narrow definition, one that allows for a
and b
to have differences in data so long as they are not "comparison-salient".
That being said:
Is it then my responsibility to explicitly annotate the return type as
std::weak_ordering
in this case to make it semantically accurate?
Yes. The compiler cannot know what is "substitutable" and what is not. This is a semantic property, and it is always up to the programmer to define it.
And yes, your Multiplication
struct is not substitutable.