Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Clarifying std::weak_ordering with C++20 Spaceship Operator for a Struct

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?

like image 375
RaisinCrab Avatar asked Feb 24 '26 15:02

RaisinCrab


1 Answers

According to the docs, std::strong_ordering requires that equivalent values be indistinguishable, as opposed to std::weak_ordering.

This is incorrect. It requires "substitutability", which in the standard is defined as:

the property that f(a) == f(b) is true whenever a == b is true, where f 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.

like image 151
Nicol Bolas Avatar answered Feb 27 '26 05:02

Nicol Bolas



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!