none
Why doesn't the spaceship operator generate equality operations when I try using a custom operator<=>? RRS feed

  • Question

  • The following code gives rise to compiler errors for the == and != operations. I've tried with both the latest MS & GCC compilers so I presume it's a lack of understanding on my part.

    Changing the #if 0 to 1 - so using the default spaceship operator, all compiles fine.

    #include <iostream>
    #include <compare>
    
    struct Basics {
        int i;
        char c;
    #if 0
        auto operator<=>( const Basics& ) const = default;
    #else
        std::strong_ordering operator<=>( const Basics& rhs ) const
        {
            if ( auto cmp = i <=> rhs.i; cmp != 0 ) return cmp;
            return c <=> rhs.c;
        }
    #endif
        Basics( int ii, char cc )
        {
            i = ii;
            c = cc;
        }
    };
    
    int main()
    {
        Basics b1( 1, 'a' );
        Basics b2( 1, 'b' );
    
        std::cout << (b1 == b2);
        std::cout << (b1 != b2);
        std::cout << (b1 < b2);
        std::cout << (b1 <= b2);
        std::cout << (b1 > b2);
        std::cout << (b1 >= b2);
    }
    

    Looking at documentation, I'd expect that returning strong_ordering would generate all the operations.

    Can anyone explain why - to a compiler layman?

    Saturday, November 16, 2019 5:58 PM

Answers

  • Maybe “==” and “!=” do not automatically rely on “<=>” because it is sometimes cheaper to determine that two values are not equal than it is to determine in which way they are unequal” [http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1190r0.html].

    Seems that the error discourages the practice of using potentially inefficient implementation by default. But it is possible to confirm explicitly that “==” and “!=” can be based on “<=>”:

       bool operator == ( const Basics& rhs ) const

       {

          return ( *this <=> rhs ) == 0; // or std::is_eq( *this <=> rhs );

       }

     

    • Edited by Viorel_MVP Sunday, November 17, 2019 8:58 AM
    • Marked as answer by David LowndesMVP Wednesday, November 20, 2019 12:15 PM
    Sunday, November 17, 2019 8:54 AM
  • It's because the versions of the compilers you tried both implement p1185 (https://wg21.link/p1185) which changes the rules of which operators are considered for rewrite rules.
    Tuesday, November 19, 2019 10:30 AM

All replies

  • Maybe “==” and “!=” do not automatically rely on “<=>” because it is sometimes cheaper to determine that two values are not equal than it is to determine in which way they are unequal” [http://open-std.org/JTC1/SC22/WG21/docs/papers/2018/p1190r0.html].

    Seems that the error discourages the practice of using potentially inefficient implementation by default. But it is possible to confirm explicitly that “==” and “!=” can be based on “<=>”:

       bool operator == ( const Basics& rhs ) const

       {

          return ( *this <=> rhs ) == 0; // or std::is_eq( *this <=> rhs );

       }

     

    • Edited by Viorel_MVP Sunday, November 17, 2019 8:58 AM
    • Marked as answer by David LowndesMVP Wednesday, November 20, 2019 12:15 PM
    Sunday, November 17, 2019 8:54 AM
  • Possibly!

    But from my brief reading of that (if that is the situation here) is that it'd probably be something that would give rise to a warning rather than an error?

    Sunday, November 17, 2019 10:44 AM
  • It's because the versions of the compilers you tried both implement p1185 (https://wg21.link/p1185) which changes the rules of which operators are considered for rewrite rules.
    Tuesday, November 19, 2019 10:30 AM
  • OK, some thoughts on this...

    1. Why is there an inconsistency (from my perspective) between implementing <=> and what = default does? Inconsistency is rarely good. The example types are simple, I was writing a custom <=> to eliminate possible issues with the default generated operations suffering from re-ordering of the member variables.

    2. Why is there no warning/explanatory message that this is the root of no equality operation being generated?

    3. None of the examples I came across mentioned this behaviour, so it is confusing.

    4. Aren't compilers going to be smart enough to determine whether there would be a performance issue with the generated equality operators?

    Tuesday, November 19, 2019 11:09 AM
  • 1. Looking at the meeting notes from San Diego where this part of the paper was agreed on, it seems this was contested a bit, but I can't find clear arguing points for it. Might be worth asking Barry about it.

    2. That would be a nice QoI feature. Would you mind opening a ticket on Developer Community for this? https://developercommunity.visualstudio.com/content/idea/post.html?space=623.

    3. Which examples? cppreference? Maybe worth suggesting an edit or putting a note that something needs updating.

    4. Not in the general case at least. My understanding is that this was introduced in order to not bake hard-to-find performance issues into the language. Tooling support could alleviate that somewhat, but this is a conservative approach.

    Tuesday, November 19, 2019 11:31 AM
  • 1. Barry?

    Regarding the inconsistency with default, does the compiler generate efficient equality operators when default is used?

    2. Suggestion posted: https://developercommunity.visualstudio.com/idea/826087/could-we-have-an-explicit-warning-that-indicates-t.html

    3. 

    Under "Strong ordering": https://en.cppreference.com/w/cpp/language/default_comparisons

    I'm sure there were others I encountered too, but I can't quickly find them now.

    Tuesday, November 19, 2019 3:50 PM
  • 1. Sorry, Barry Revzin, the author of the paper which made the change.

    You can see the definition for what the defaults should generate in section 3.2 of the paper.

    2. Thank you, I've sent it to the relevant team so they can prioritize work.

    3. Thanks, I've made a note on the discussion page for the maintainers that the examples are no longer correct: https://en.cppreference.com/w/Talk:cpp/language/default_comparisons

    Wednesday, November 20, 2019 10:53 AM
  • Barry has referred me to this thread where the same issue was raised a few days ago: https://stackoverflow.com/questions/58780829/equality-operator-does-not-get-defined-for-a-custom-spaceship-operator-implement

    I still feel that the inconsistency is confusing and would have been less confusing to have required both <=> and == operators defined even if they both were = default.

    Wednesday, November 20, 2019 2:48 PM