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 actually returns std::strong_ordering by default
auto operator<=>(MultiplicationExpression rhs) const
{
return (multiplicand * multiplicator) <=> (rhs.multiplicand * rhs.multiplicator);
}
};
Is it then my responsibility to explicitly annotate the return type as std::weak_ordering in this case to make it semantically accurate?
>Solution :
According to the docs,
std::strong_orderingrequires 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 == bis true, wherefdenotes 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_orderingin 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.
Note that it’s easy to fix this:
std::weak_ordering operator<=>(Multiplication const& rhs) const = default;
You don’t even have to define the function.