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

C++ 三向比较运算符成员与非成员实现,c++,comparison-operators,c++20,spaceship-operator,C++,Comparison Operators,C++20,Spaceship Operator,在以下情况下,双向比较运算符应为非成员函数: 您希望第一个操作数的类型不是此类 您需要隐式类型转换两个操作数中的任意一个 新的C++20三向比较运算符具有对称生成规则。表达式的名称查找a@b,其中@是一个双向比较运算符,按a@b、ab和ba(在从重载分辨率集中选择最佳匹配时,如果出现歧义,请按照此优先顺序)。有关详细信息,请参阅。这意味着运算符可以是成员函数,但仍允许第一个操作数不是此类类型 然而,该文件包含以下注释: 通常,运算符应该只是一个成员函数;你还是会的 由于对称生成,因此获取每个

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

  • 您希望第一个操作数的类型不是此类
  • 您需要隐式类型转换两个操作数中的任意一个
新的C++20三向比较运算符具有对称生成规则。表达式的名称查找
a@b
,其中
@
是一个双向比较运算符,按
a@b
ab
ba
(在从重载分辨率集中选择最佳匹配时,如果出现歧义,请按照此优先顺序)。有关详细信息,请参阅。这意味着运算符
可以是成员函数,但仍允许第一个操作数不是此类类型

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

通常,运算符应该只是一个成员函数;你还是会的 由于对称生成,因此获取每个参数的转换 §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"));  // ??
}
structfoo
{
foo(int const x)
:数据{x}{}
foo(std::string\u视图x)
:data{std::stoi(x.data())}{}
friend自动操作员(foo const&lhv、foo const&rhv)无例外
{
返回lhv.data rhv.data;
}
私人:
int数据;
};
int main()
{
断言(foo{42}==foo{“42});//确定
断言(42==std::string_视图(“42”);/??
}
以下是一个说明性(但不一定实用)示例:

结构A{ int i; }; 结构B{ B(A):我(A.i){} int i; }; 强序算子(B常数和lhs,B常数和rhs){ 返回左一右一; } A{2}==A{2};//好吧,没错 A{2} 我们发现候选者在全局范围内使用两个
B
s,这是可行的,所以我们转换这两个参数并使用它。如果该运算符是类中声明的成员函数或非成员
friend
,则名称查找不会找到它



请注意,在OP中,
被声明为类中的非成员
朋友。这意味着名称查找不会在
42==string\u视图(“42”)
中找到它,因为这两个参数都不是
foo
。您需要添加一个普通的非成员声明,以使其在此类查找中可见。

感谢您提供的示例和对运算符声明方式的注释。我将示例更改为实际意图。@马吕斯对不起,我恢复了您的编辑。请不要编辑问题以使答案无效。这个问题很好,强调这个问题很重要。
struct silly{silly(std::vector const&v):s(v.size()){};std::size_t s=-1;friend std::strong_排序运算符(silly const&lhs,silly const&rhs){return lhs.s rhs.s}
--即使两个参数都不是
愚蠢的
std::vector{}std::vector{}
仍然可以找到方法并进行转换@Yakk AdamNevraumont这是因为非默认的三向比较运算符(
)不会生成其他比较运算符。@Yakk AdamNevraumont抱歉,我以为您使用了
=
作为示例。您需要对
std::vector
进行部分模板专门化。
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