简体   繁体   English

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

[英]Three-way comparison operator member vs non-member implementation

Two-way comparison operators should be non-members functions if: 在以下情况下,双向比较运算符应为非成员函数:

  • you want the first operand to be of a type that is not this class 您希望第一个操作数的类型不是此类
  • you want implicit type conversion any of the two operands 您想要两个操作数中的任何一个进行隐式类型转换

The new C++20 three-way comparison operator has symmetric generation rules. 新的C ++ 20三向比较运算符具有对称的生成规则。 The name lookup for an expression a@b , where @ is a two-way comparison operator, is done in the order a@b , a<=>b and b<=>a (with this order of preference in case of ambiguity when selecting the best match from the overload resolution set). 表达式a@b的名称查找(其中@是一种双向比较运算符)以a@ba<=>bb<=>a顺序进行(在模棱两可的情况下,此优先顺序为从过载分辨率设置中选择最佳匹配时)。 See P0515R2 for details. 有关详细信息,请参见P0515R2 This means the operator <=> can be a member function and still allow the first operand to not be of this class type. 这意味着运算符<=>可以是成员函数,并且仍然允许第一个操作数不属于此类。

The paper, however, contains this note: 但是,该文件包含以下注释:

Normally, operator<=> should be just a member function; 通常,operator <=>应该只是成员函数。 you will still get conversions on each parameter because of the symmetric generation rules in §2.3. 由于§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. 在极少数情况下,您还希望同时支持两个参数的转换(要启用两个都不属于此类型的对象的比较,而是要使用此类型的比较功能),请使其成为非成员朋友。

If I understand this correctly it says non-member implementation should be only needed if implicit conversion on both operands at the same time is needed? 如果我正确理解这一点,它说仅当需要同时对两个操作数进行隐式转换时才需要非成员实现吗? Is that correct? 那是对的吗? Can I see an actual example when that is needed? 我可以在需要时看到一个实际示例吗? I am thinking of this although it does not seem like a valid example: 我正在考虑这一点,尽管它似乎不是一个有效的示例:

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

Here's an illustrative (though not necessarily practical) example: 这是一个说明性(尽管不一定实际)示例:

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

We find the candidate taking two B s at global scope, and it's viable, so we convert both arguments and use it. 我们发现候选者在全局范围内取两个B ,并且它是可行的,因此我们将两个参数都转换并使用它。 If that operator was either a member function or a non-member friend declared within the class, name lookup wouldn't have found it. 如果该运算符是在类中声明的成员函数或非成员friend ,则名称查找将找不到它。


Note that in the OP, <=> is declared as a non-member friend within the class. 请注意,在OP中, <=>被声明为该类中的非成员friend This means that name lookup would not find it for 42 == string_view("42") , since neither of those arguments is a foo . 这意味着对于42 == string_view("42") ,名称查找将找不到它,因为这些参数都不是foo You would need to add a normal non-member declaration to make it visible for such lookup. 您将需要添加一个普通的非成员声明,​​以使其对于此类查找可见。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM