覆盖枚举类的 c++20 太空船运算符

Tom*_*ken 2 c++ enums operator-overloading spaceship-operator c++20

我正在努力为枚举类提供新的宇宙飞船运算符。让我们看下面的例子:

#include <cstdio>
#include <iostream>
#include <compare>
#include <cstdint>

enum class Animals : uint8_t
{
  Bird = 27, //those values are just for making a point
  Tiger = 5,
  Ant = 100,
  Snake = 45,
  Wale = 17
};

//auto operator<=(const Animals& lhs, const Animals& rhs) = delete;
//auto operator>=(const Animals& lhs, const Animals& rhs) = delete;
//auto operator<(const Animals& lhs, const Animals& rhs) = delete;
//auto operator>(const Animals& lhs, const Animals& rhs) = delete;

auto operator<=>(const Animals& lhs, const Animals& rhs)
{
    std::cout << "comparing via overloaded <=> operator\n";
  //order the animals by their size in real life
  // Ant < Bird < Snake < Tiger < Wale
  //for this MVCE only Ant < Tiger is in here:
  if(lhs == Animals::Ant && rhs == Animals::Tiger)
    return -1;
  return 0; //all unimplemented ones are treated as equal
}

int main(void)
{
  if(Animals::Ant < Animals::Tiger)
    std::puts("success (do I see the prompt of the overloaded operator?)");
  else
    std::puts("seems to use uint8_t comparison instead");

  return 0;
  
}
Run Code Online (Sandbox Code Playgroud)

但显然我在这里犯了一些错误,正如我的main()仍然告诉我的那样,蚂蚁比老虎更大。正如您所看到的,我尝试显式删除默认的比较运算符,以强制编译器使用我的自定义太空船一,但没有成功。

当我显式调用时,auto result = Animals::Ant <=> Animals::Tiger我得到一个ambiguous overload for 'operator<=>' (operand types are 'Animals' and 'Animals'). 但这似乎与我的操作员签名有关(使用const动物代替)。

是否可以覆盖我的枚举的运算符(而不干扰其基本类型“uint8_t”的运算符?

Bar*_*rry 8

你的有两个问题operator<=>

  1. 它需要按值获取枚举,而不是通过引用 const,以便抑制内置候选者
  2. 它需要返回比较类别之一,而不是int. 在这种情况下可能std::weak_ordering是正确的。

那是:

constexpr auto operator<=>(Animals lhs, Animals rhs) -> std::weak_ordering
{
  //order the animals by their size in real life
  // Ant < Bird < Snake < Tiger < Wale
  //for this MVCE only Ant < Tiger is in here:
  if(lhs == Animals::Ant && rhs == Animals::Tiger)
    return std::weak_ordering::less;
  return std::weak_ordering::equivalent;
}
Run Code Online (Sandbox Code Playgroud)

也就是说,如何处理重写候选者存在实现分歧<=>。clang 和 msvc 实现了可能应该的规则,即我们的用户声明operator<=>抑制所有内置的关系和三向比较运算符,以便Animals::Ant < Animals::Tiger调用我们的operator<=>. 但是 gcc 实现了技术上规则实际上字面上所说的内容,即Animals::Ant <=> Animals::Tiger评估我们的运算符,但 using<不评估。有一个为此开放的 gcc 错误报告 ( #105200 ),其中一位 gcc 开发人员指出了措辞问题。在我看来,这是一个措辞问题,而不是实际的设计意图问题,因此我将就此提出一个核心问题(#205)。

为了使其在 gcc 上工作,您还必须自己检查并添加这些内容(注意:始终按值):

constexpr auto operator<(Animals lhs, Animals rhs) -> bool {
    return (lhs <=> rhs) < 0;
}

constexpr auto operator<=(Animals lhs, Animals rhs) -> bool {
    return (lhs <=> rhs) <= 0;
}

constexpr auto operator>(Animals lhs, Animals rhs) -> bool {
    return (lhs <=> rhs) > 0;
}

constexpr auto operator>=(Animals lhs, Animals rhs) -> bool {
    return (lhs <=> rhs) >= 0;
}
Run Code Online (Sandbox Code Playgroud)