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

2024-01-29

如果出现以下情况,双向比较运算符应该是非成员函数:

  • 您希望第一个操作数的类型不是此类
  • 您想要对两个操作数中的任何一个进行隐式类型转换

新的 C++20 三路比较运算符具有对称生成规则。表达式的名称查找a@b, where @是双向比较运算符,按顺序完成a@b, a<=>b and b<=>a(在从重载解析集中选择最佳匹配时出现歧义时,使用此优先顺序)。看P0515R2 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0515r2.pdf了解详情。这意味着运营商<=>可以是成员函数,并且仍然允许第一个操作数不是此类类型。

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

通常情况下,operator 应该只是一个成员函数;你仍然会 由于对称生成,可以对每个参数进行转换 §2.3 中的规则。在极少数情况下您也想支持 同时对两个参数进行转换(以启用比较 两个对象都不是这种类型,但是使用这种类型的 比较功能),使其成为非会员好友。

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

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

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


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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

三路比较运算符成员与非成员实现 的相关文章

随机推荐