让编译器通过 spaceship-operator [duplicate] 编写运算符==、<、> 等

Letting compiler write operator==, <, > etc. via spaceship-operator [duplicate]

提问人:glades 提问时间:9/12/2023 最后编辑:πάντα ῥεῖglades 更新时间:9/12/2023 访问量:104

问:

我正在和宇宙飞船操作员碰碰运气。假设我有一个类似变体的对象(我使用固定的模板参数方便地从中派生),并且我想定义运算符 ==、<、>、!= 等......为了便于比较,我想我可以根据包含的类型来飞船,并让编译器自己定义所有运算符:std::variant

演示

#include <compare>
#include <iostream>
#include <variant>
#include <string>

class JSON : public std::variant<std::monostate, double, std::string> {
public:
    using variant::variant;

    auto operator<=>(std::string str) const {
        return std::get<std::string>(*this) <=> str;
    }
    auto operator<=>(double d) const {
        return std::get<double>(*this) <=> d;
    }
};
  
int main()
{
    JSON myjson = 2.3;

    if (myjson == 2.3) {
        std::cout << "JSON was 2.3" << std::endl;
    }
}

然而,这个 apporach 产生了:

<source>: In function 'int main()':
<source>:22:16: error: no match for 'operator==' (operand types are 'JSON' and 'double')
   22 |     if (myjson == 2.3) {
      |         ~~~~~~ ^~ ~~~
      |         |         |
      |         JSON      double

我本来以为编译器现在知道如何为我的变体对象编写,以防 rhs 是双精度或 rhs 是字符串。如果变体包含不同的替代方案,我可以使用 std::get 向我抛出。operator==

C++ 比较 std-variant spaceship-operator

评论

1赞 康桓瑋 9/12/2023
operator==当声明为 时才合成,这不是您的情况,因此仍然需要为您的类提供。operator<=>defaultoperator==
0赞 康桓瑋 9/12/2023
我认为只有在您的示例中提供才能解决问题。auto operator<=>(const JSON& d) const = default
0赞 glades 9/12/2023
@康桓瑋 确实如此!发生了什么事情?我猜编译器使用 std::variant(double) 将 double 隐式转换为 JSON,然后使用内置运算符 == 来比较两个 JSON 对象?
0赞 glades 9/12/2023
@康桓瑋 再次反思一下,它似乎可以通过拉入基类运算符来实现<=>,不是吗?但是,这不会编译:godbolt.org/z/q1b8Y6shj
1赞 康桓瑋 9/12/2023
起作用的原因是 被转换为 ,所以比较两个 s 将调用 的比较函数。您提供的示例不起作用,因为您正在比较 ,这与比较函数不匹配。auto operator<=>(const JSON& d) const = default doubleJSONJSONvariantdoubleJSONvariant

答:

3赞 wohlstad 9/12/2023 #1

默认比较(自 C++ 20 起):

根据任何运算符<=>重载的规则,默认的 <=> 重载>还允许将类型与 <、<=、> 和 >= 进行比较。

如果 operator<=> 是默认值,并且根本没有声明 operator==, 则 operator== 是隐式默认的。

正如您在上面的链接中看到的,这是唯一提到的基于 的隐式默认值。operator==operator<=>

如果您的情况不是 ed,因此上述内容不适用。
因此,您需要提供(或者在一般情况下,如果可能的话,根据操作数类型自行提供)。
operator<=>defaultoperator==default

注意:

正如@康桓瑋所评论的那样,在您的具体情况下,您实际上可以:defaultoperator<=>

auto operator<=>(const JSON& d) const = default;

如上所述,它之所以有效,是因为被转换为 ,因此比较两个 s 将调用 的比较方法。doubleJSONJSONvariant

评论

0赞 glades 9/12/2023
你能添加如何解决它吗(参见@康桓瑋对OP的评论)?
0赞 HolyBlackCat 9/12/2023
默认值不是根据 ,而是通过直接比较字段来实现它,不是吗?如果操作数类型不匹配,我认为您不能默认它。==<=>
1赞 wohlstad 9/12/2023
@glades添加了更新。
0赞 wohlstad 9/12/2023
@HolyBlackCat我认为你是对的。添加了说明。