C++ 宇宙飞船运算符和用户定义类型:仅比较属性的子集

C++ spaceship-operator and user-defined types: comparing a subset of attributes only

提问人:ABu 提问时间:7/9/2022 更新时间:7/9/2022 访问量:1744

问:

我有两个班级。第一个组成第二个。这两个类都有自己的合成属性,该属性不与排序或比较协作。此外,我想在第二个容器上使用,所以我需要实现强排序。这就是我所拥有的:std::ranges::sort

struct basic
{
    std::string synthetized; // string representation of the next field.
    unsigned value;
    unsigned property;

    friend bool operator<(basic const& a, basic const& b)
    { return a.value < b.value or (a.value == b.value and a.property < b.property); }
};

struct composed
{
   basic value;
   custom_type meta;

   friend bool operator<(composed const& a, composed const& b)
   { return a.value < b.value; }
};

int main()
{
   std::vector<composed> container;
   // populating container

   // Compilation error here.
   std::ranges::sort(container);
}

我应该如何适当有效地超载?虽然我需要的是对向量进行排序,仅此而已(我可以去传统),我想知道如何为两个类提供完整的关系功能(<、<=、==、!= 等)给两个类,但忽略 和 ,并且不做任何愚蠢的性能方面的事情。operator<=>std::sortsynthetizedmeta

C++ 排序 C++20 相等

评论

0赞 Passer By 7/9/2022
你写的是宇宙飞船操作员而不是......?operator<
0赞 ABu 7/9/2022
它将比较字符串和元,他们不希望这种情况发生。此外,甚至根本没有可比性。meta
0赞 Passer By 7/9/2022
你知道你可以写一个自定义吗?operator<=>
0赞 Goswin von Brederlow 7/9/2022
你把你的结构体定义为他们自己的朋友,这很可爱,但完全没有意义,运算符的签名都是错误的。类内运算符具有隐式参数,因此他们只接受一个参数,即右侧。this
0赞 ABu 7/9/2022
@GoswinvonBrederlow这只是我习惯的一种模式。无论如何,如果将 作为函数成员实现,则不允许自动转换左侧对象。例如,如果有一个整数的转换构造函数,将不起作用,而作为外部重载将起作用。让它成为朋友的意义有两个原因:1.它是自动内联的。2. 如果他们的成员是私人的,您无需转发声明即可访问。这些是为什么以这种方式实现运算符的经典众所周知的原因(称为规范实现)operator<composed3 < x<

答:

4赞 Ted Lyngmo 7/9/2022 #1

我应该如何适当有效地超载?operator<=>

实现这两者的最简单方法可能是使用 std::tie 并使用 operator<=> 的现有函数模板来表示类型:tuple

template< class... TTypes, class... UTypes >
constexpr /* see link */ operator<=>( const std::tuple<TTypes...>& lhs,
                                      const std::tuple<UTypes...>& rhs );

例:

#include <tuple>

struct basic {
    std::string synthetized; // excluded from comparisons
    unsigned value;
    unsigned property;

    friend auto operator<=>(basic const& a, basic const& b) {
        return std::tie(a.value, a.property) <=> std::tie(b.value, b.property);
    }
};

struct composed {
    basic value;
    custom_type meta; // excluded from comparisons

    friend auto operator<=>(composed const& a, composed const& b) {
        return a.value <=> b.value;
    }
};

您还应该添加 which 也将用于 这样您就不必重载了 .operator==!=operator!=

2赞 康桓瑋 7/9/2022 #2

我想知道如何给两个类提供完整的关系 功能(<、<=、==、!= 等)添加到两个类,但忽略 合成和元,不做任何愚蠢的事情 性能方面。

为您的类型定义比较成员函数

#include <string>

struct basic
{
    std::string synthetized; // string representation of the next field.
    unsigned value;
    unsigned property;

    constexpr auto operator<=>(const basic& other) const noexcept {
      if (auto c = value <=> other.value; c != 0) 
        return c;
      return property <=> other.property;
    }

    constexpr bool operator==(const basic& other) const noexcept {
      return value == other.value && property == other.property;
    }
};

struct composed
{
   basic value;
   custom_type meta;

   constexpr auto operator<=>(const composed& other) const noexcept {
    return value <=> other.value; 
   }

   constexpr bool operator==(const composed& other) const noexcept {
    return value == other.value; 
   }
};

请注意,在您的示例中不会进行合成,因为它不是默认值,因此您仍然需要定义您的类型以满足total_ordered_withoperator<=>operator==operator==

演示

评论

0赞 Goswin von Brederlow 7/9/2022
您可以默认 or,它将用于所有内容。operator==operator!=<=>
1赞 Goswin von Brederlow 7/9/2022
怎么样 ?struct composed : basic { custom_type meta; using basic::operator<=>; using basic::operator==;};
1赞 Barry 7/10/2022
@Goswin Defaulting 不会使用 ,它将生成成员平等。==<=>
0赞 Goswin von Brederlow 7/10/2022
@Barry该死的,我看错了。关于默认operator@将使其使用的部分仅适用于 。<=>< > <= >=