You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何为编译时常量字符串类实现operator<=>后仍需补充operator==?

关于C++中operator<=>与operator==的疑问

问题背景

我定义了一个代表编译时常量字符串的类Foo,它包含隐式转换为std::string_view的运算符,希望通过operator<=>实现与std::string_view、const char*、const std::string&等类字符串类型的比较。

初始代码

最初的代码仅支持Foo自身及与std::string_view的比较:

//! 代表字符串"foo"的单态类:
struct Foo {
    constexpr operator std::string_view() const noexcept {
        return "foo";
    }

    //! 支持与自身比较
    friend constexpr auto operator<=>(const Foo&, const Foo&) = default;
};

这符合预期,因为转换运算符可将Foo转为std::string_view进行比较。

添加模板化operator<=>后的情况

随后添加了模板化的operator<=>,试图支持与所有可和std::string_view比较的类型:

//! 支持与所有可和std::string_view比较的类型比较?
    friend constexpr auto operator<=>(const Foo& foo, const auto& other) {
        return static_cast<std::string_view>(foo) <=> other;
    }

此时可以实现与const char*、std::string的<、<=>双向比较,但无法使用operator==进行相等判断。

添加模板化operator==后的解决

当添加以下模板化的operator==后,所有比较均正常编译:

friend constexpr bool operator==(const auto& other, const Foo& self) {
        return other == static_cast<std::string_view>(self);
    }

核心疑问

为何需要额外添加operator==?我原以为operator<=>(const T&, const U&)支持这两种类型的双向相等比较,添加反向的operator<=>也无济于事,希望得到解释。

原因解释

这是C++20三路比较运算符的设计规则导致的:

  • operator<=>不自动生成反向相等判断:当你定义operator<=>(Foo, auto),它仅处理Foo作为左操作数的顺序比较(包括<、>、<=、>=以及<=>本身),但不会自动推导生成auto == Foo的相等判断重载。相等判断的重载匹配规则更严格,不会通过隐式转换或三路比较的反向推导来生成。
  • 相等判断的匹配优先级问题:当写other == foo(比如std::string("foo") == Foo{})时,编译器会优先查找直接的operator==(const std::string&, const Foo&)重载。由于你的operator<=>是Foo作为左操作数的模板,无法反向适配右操作数的相等判断,且std::string的operator==也无法直接通过隐式转换匹配Foo(会因候选重载歧义或优先级问题失败)。
  • 三路比较与相等判断分离:C++20中,operator<=>负责顺序比较,operator==负责相等性判断,二者是独立的重载。即使定义了operator<=>,编译器也不会自动生成跨类型的operator==重载,尤其是涉及模板或隐式转换的场景。

简言之:operator<=>管「谁大谁小」,operator==管「是否相等」,跨类型的相等判断需要显式提供对应重载,无法依赖三路比较运算符自动推导。

内容的提问来源于stack exchange,提问作者Ben

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 01:10:36