是否有任何 C++ 运算符重载是基于其他运算符自动提供的?

Are any C++ operator overloads provided automatically based on others?

假设我正在编写一个 int 包装器并且需要提供每个运算符重载。作者必须列出每一个,还是可以根据作者提供的内容自动生成任何一个? Can/does 编译器从现有运算符中推断出任何新的自动定义运算符?

如果我定义 operator==,它会自动给我一个 operator!= 吗?或者反之亦然?

如果我定义 operator++(),我是否可以免费获得 operator++(int)?或者反之亦然?

+=类型的生意怎么样?它可以将 operator+ 的现有定义与 operator= 结合起来生成 operator+= 吗?理论上应该可以,但是真的可以吗?

关于 >=< 等的相同问题,或者我是否必须完整列出 >>>= 的定义, <=?

没有

C++ 在核心语言中没有推理规则,所以即使定义说 + 它也不会假设任何关于 +=...只是(就语言而言)完全无关。

考虑到标准库中的 <<(左移位运算符)已被重载为表示 "output to stream"... 只是因为外观以及合理的优先级和关联性。

在核心语言中,各种运算符是独立的。有些是根据其他运算符定义的,但是如果运算符调用的重载解析失败,则不会尝试根据其他运算符来表达该调用。当需要时,程序员可以很容易地表达出来(相反,关闭这种机器可能会更困难)。

std::rel_ops 中有一组关系运算符重载可供客户端代码使用,根据 <== 定义。

您可以轻松编写一个 mixin-class,它提供 <== 或三值 compare 函数方面的关系运算符.这就是 Curiously Recurring Template Pattern, called the Barton-Nackman trick.

的最初动机

C++ 20 运算符<=>

似乎在 C++20 中,std::rel_ops 已被弃用,默认 <=> 将自动免费提供 ==, !=, <, >, <=, >=

改编自https://en.cppreference.com/w/cpp/language/default_comparisons

main.cpp

#include <cassert>
#include <compare>
#include <set>

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

int main() {
    Point pt1{1, 1}, pt2{1, 2};

    // Just to show it Is enough for `std::set`.
    std::set<Point> s;
    s.insert(pt1);

    // Do some checks.
    assert(!(pt1 == pt2));
    assert( (pt1 != pt2));
    assert( (pt1 <  pt2));
    assert( (pt1 <= pt2));
    assert(!(pt1 >  pt2));
    assert(!(pt1 >= pt2));
}

编译并运行:

sudo apt install g++-10
g++-10 -ggdb3 -O0 -std=c++20 -Wall -Wextra -pedantic -o main.out main.cpp
./main.out

详情请见:

在 Ubuntu 20.04、GCC 10.2.0 上测试。

C++20 添加了一项功能,允许语言为关系(<><= 做一些事情,比如 , >=) 和相等运算符 (==!=).

当使用相等运算符时,系统可以尝试颠倒操作数的顺序(用于不同类型的相等测试)以及取反结果以找到合适的 operator== 重载。也就是说,如果您只实现 operator== 用于 AB 的相等性测试,这也将允许您对 BA 进行相等性测试,以及不等式测试他们也是。

请注意,编译器不会 为您生成运算符函数。相反,它修改了调用运算符的实际位置。也就是说,它将 b != a 变成 !(a == b) 以找到合适的 == 运算符。

对于 <=>,它以几乎相同的方式应用于所有关系运算符(但 而非 相等运算符)。系统将根据需要将 a < b 重写为 (a <=> b) < 0(b <=> a) > 0 以找到匹配的重载 <=> 运算符。

此外,您可以 = default 任何比较运算符,它按子对象方式执行,以便按顺序比较相关类型的子对象(您只能默认比较相同类型)。如果您默认使用 == 运算符,那么根据上述规则,您也可以有效地获得 !=。如果您默认 <=>,您将通过重写获得所有关系运算符。

如果您默认 <=> 而没有 默认 ==,则系统将 生成默认 ==,所以默认 <=> 单独给你所有的比较运算符。