三向比较运算符成员与非成员实现

Three-way comparison operator member vs non-member implementation

双向比较运算符应该是非成员函数,如果:

新的C++20 三向比较运算符具有对称生成规则。表达式 a@b 的名称查找,其中 @ 是双向比较运算符,按顺序 a@ba<=>bb<=>a(使用在从重载解析集中选择最佳匹配时出现歧义的情况下的优先顺序)。有关详细信息,请参阅 P0515R2。这意味着运算符 <=> 可以是成员函数,并且仍然允许第一个操作数不是这种 class 类型。

然而,该论文包含以下注释:

Normally, operator<=> should be just a member function; you will still get conversions on each parameter because of the symmetric generation rules in §2.3. In the rare case that you also want to support conversions on both parameters at the same time (to enabling compare two objects neither of which is of this type, but using this type’s comparison function), make it a non-member friend.

如果我理解正确的话,它说只有在需要同时对两个操作数进行隐式转换时才需要非成员实现?那是对的吗?我可以在需要时查看实际示例吗?我正在考虑这个,虽然它看起来不是一个有效的例子:

struct foo
{
   foo(int const x) 
      : data{ x } {}
   foo(std::string_view x) 
      : data{std::stoi(x.data())}{}

   friend auto operator<=>(foo const & lhv, foo const & rhv) noexcept
   {
      return lhv.data <=> rhv.data;
   }

private:
   int data;
};


int main()
{
   assert(foo {42} == foo {"42"});        // OK
   assert(42 == std::string_view("42"));  // ??
}

这是一个说明性的(虽然不一定实用)示例:

struct A {
    int i;
};

struct B {
    B(A a) : i(a.i) { }

    int i;
};

strong_ordering operator<=>(B const& lhs, B const& rhs) {
    return lhs.i <=> rhs.i;
}

A{2} == A{2}; // okay, true
A{2} < A{1};  // okay, false

我们发现候选人在全局范围内使用了两个 B,这是可行的,因此我们转换两个参数并使用它。如果该运算符是成员函数或在 class 中声明的非成员 friend,名称查找将找不到它。


请注意,在 OP 中,<=> 在 class 中被声明为非成员 friend。这意味着名称查找不会为 42 == string_view("42") 找到它,因为这些参数都不是 foo。您需要添加一个普通的非成员声明以使其对此类查找可见。