C++ Logo

std-proposals

Advanced search

Re: [std-proposals] Standard attribute [[nocompare]] for defaulted comparisons

From: Arthur O'Dwyer <arthur.j.odwyer_at_[hidden]>
Date: Mon, 16 Jan 2023 22:56:33 -0500
On Mon, Jan 16, 2023 at 4:26 PM joeri _ via Std-Proposals <
std-proposals_at_[hidden]> wrote:

> The introduction of a standard attribute [[nocompare]] which can be used
> to indicate that a suboject of T should be omitted from a defaulted
> comparison.
>
>
>
> struct s {
>
> int id;
>
> [[nocompare]] std::string name;
>
> auto operator<=>(s const&) const = default;
>
> };
>

This wouldn't be a good use of an attribute — not because "attributes
should be ignorable," but mainly because attributes are (like keywords)
*expensive* to specify and implement and teach. It seems like there ought
to be a clever way to get this behavior without any language extensions.
The first thing that came to mind was to wrap `name_` in a helper type that
would always compare equal; something like this:
    struct S {
      int id_;
      struct Helper {
        std::string name_;
        auto operator<=>(const Helper&) const { return
std::strong_ordering::equal; }
        auto operator==(const Helper&) const { return true; }
      } h;
      auto operator<=>(const S&) const = default;
    };

You can even get the inner `<=>` and `==` for free(-ish) by making `Helper`
inherit from `std::monostate`, or any other type whose `operator<=>` does
the right thing.
    // https://godbolt.org/z/v4nzKjbb5
    struct S {
      int id_;
      struct Helper : std::monostate {
        Helper(std::string n) : name_(std::move(n)) {}
        std::string name_;
      } h;
      S(int id, std::string name) : id_(id), h(std::move(name)) {}
      auto operator<=>(const S&) const = default;
    };
I'm not saying this solution *as-is* should be considered better or cleaner
than `[[nocompare]] std::string name_;` — but it suggests to me that there
is *some* clever idiom waiting to be discovered here within the current
language.

The basic principle here is "Rule of Zero": strive to =default all your
special members, including the "honorary" special members `<=>` and `==`.
That means if you don't want some field to participate in the comparison
(or to be copied, or to be swapped, or whatever), you should pull it out
into a helper class so that the top-level business-logic class can simply
=default its special members.

–Arthur

Received on 2023-01-17 03:56:46