首页 > 解决方案 > 三向比较运算符成员与非成员实现

问题描述

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

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

但是,该文件包含以下注释:

通常, 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"));  // ??
}

标签: c++comparison-operatorsc++20spaceship-operator

解决方案


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

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在全局范围内采用两个 s,这是可行的,因此我们转换两个参数并使用它。如果该运算符是在类中声明的成员函数或非成员friend,则名称查找将找不到它。


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


推荐阅读