【问题标题】:Are any C++ operator overloads provided automatically based on others?是否有任何 C++ 运算符重载基于其他运算符自动提供?
【发布时间】:2015-12-25 07:58:27
【问题描述】:

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

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

如果我定义operator++(),我是否可以免费获得operator++(int)?还是反过来?

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

>=< 等的相同问题,还是我必须完整列出 >>>=<= 的定义?

【问题讨论】:

标签: c++ operator-overloading compiler-generated


【解决方案1】:

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

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

您可以轻松编写一个 mixin 类,该类以 <== 或三值 compare 函数的形式提供关系运算符。这就是 Curiously Recurring Template Pattern 的最初动机,称为 Barton-Nackman trick

【讨论】:

    【解决方案2】:

    没有。

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

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

    【讨论】:

    • 看起来你是对的,但像 ==!= 这样的东西在 99% 的应用程序中本质上是相似的......它们可以自动生成它并要求用户删除如果他们想做一些奇怪的事情,自动生成一个。
    • 请注意,通常的推断是从+=+,而不是相反。特别是c = a+ b 被推断为c = a; c += b;。原因是在 CPU 级别,+ 更复杂。它需要两个输入寄存器和一个输出寄存器。 += 只接受一个输入寄存器。
    • @MSalters:过去,我花了一些时间研究在 C++ 中定义 n 维向量类(数学意义上的向量)时,最好的代码质量是什么。我发现,根据编译器的不同,某些实现可以更好地定义 ++=,而另一些则相反,不幸的是,没有实现能像手动展开组件那样生成代码。分量数学。那是几年前的事了,可能现在编译器更聪明了,情况也更好了。
    • @6502:现代 C++ 模板代码将内联扩展并允许循环展开,因为向量大小将是编译时常量。那是 1990 年的关卡优化,但它需要现代代码。
    【解决方案3】:

    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
    

    更多详情请访问:What is the <=> operator in C++?

    在 Ubuntu 20.04、GCC 10.2.0 上测试。

    【讨论】:

      【解决方案4】:

      C++20 添加了一项功能,允许语言为关系(&lt;&gt;&lt;=&gt;=)和等式运算符(@987654325)做一些类似的事情@ 和 !=)。

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

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

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

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

      如果你默认&lt;=&gt; 没有默认==,那么系统也会生成一个默认==,所以单独默认&lt;=&gt;给你所有比较运算符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-11-26
        • 2017-02-27
        • 2016-02-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多