c++11 - 在现代 C++ 中重载算术运算符的 "best"方法是什么?

标签 c++11 operator-overloading move-semantics arithmetic-expressions

我想在 C++ 中实现一种“类似数字”的数学对象(例如,组或环中的元素)。我确信我不是唯一一个处理这个问题的人,所以可能会有大量关于什么是重载算术运算符的“最佳”方式的讨论。但是,我找不到满意的答案(虽然可能是我懒得用谷歌搜索更多)。

假设我想为 A 类重载运算符“+”。
问题是,我能想到太多不同的重载:

  • 运算符+(const A& x, const A& y)
  • 运算符+(const A& x, A&& y)
  • 运算符+(A&& x, const A& y)
  • 运算符+(A&& x, A&& y)
  • A::operator+=(const A& y) &
  • A::operator+=(const A& y) &&
  • A::operator+=(A&& y) &
  • A::operator+=(A&& y) &&

  • 第一个问题。是否所有这些重载都需要使对 A 实例的操作尽可能高效,并且尽可能地“像原始类型一样”?我认为对于“普通”情况,右值限定的 A::operator+= 不需要(或不应该)被重载。这样对吗?我认为1-4个都是必要的。例如,对于情况 3,由于 x 正在 move ,因此我们不需要分配新的空间来保存返回值,我们可以安全地重用为 x 保留的分配存储。这样对吗?

    第二个问题。我认为对于大多数这种情况,所有这些重载可能会共享很多代码。如何在不牺牲性能/等的情况下最大限度地减少代码重复?是否有任何特殊的技术/习语可以做到这一点?
    如果存在,我更喜欢通用和可扩展的方法。

    最佳答案

    不可能给出最笼统的答案,因为选择“最佳”方式将涉及对操作细节的了解。

    例如,最常见的模式(我在下面给出)对于矩阵乘法并不是那么好,因为在这种情况下,最简单的方法是声明从零开始并读取两个参数的第三个矩阵。此外,您可能希望使用惰性求值,在这种情况下,这些都不适用。

    我建议确保您的代码在所有情况下都能给出正确的答案,并且一旦您的程序运行并且在该语言方面拥有更多经验,您就可以担心微优化。

    对于类里最有效的实现方式+是修改其中一个参数,则以下两种情况涵盖所有用途,并具有强异常保证:

    A& A::operator+=(A const &y) { /* modify *this using y */ ; return *this; }
    A operator+ ( A x, A const& y ) { x += y; return x; }
    

    有关上述代码的作用和原因的更多解释,请参阅 operator overloading megathread .

    在 C++03 中,使用 A const& x 没有太大区别。而不是 A x ,但在 C++11 中,这对于第一个参数是右值的情况稍微更优化,因为现在可以从第一个参数中窃取资源。

    关于在 operator+= 上使用引用限定符的决定.为 & 单独重载没有任何好处和 && .如果您看到有人使用 & ,其基本原理不是也重载,而是为尝试使用 += 提供编译错误在右值上;理由是这很可能是一个错误。

    关于c++11 - 在现代 C++ 中重载算术运算符的 "best"方法是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37517752/

    相关文章:

    c++ - 重载运算符 '==' 时出现问题。需要能够使用模板处理字符串、 double 和日期

    c++ - 如果使用 "Promotion",为什么隐式转换序列不是最好的 ICS?

    c++ - std::function::operator bool 应该在 move 后返回 false 吗?

    c++ - 为什么使用单个赋值运算符处理复制和 move 赋值效率不高?

    c++ - 在 gdb 中调试 map<int, unique_ptr<A>>

    c++ - C++11 中的安全短路评估

    C++ 错误 : no matching function for call to 'print_size'

    c++ - 覆盖左手运算符(operator)的可能性?

    c++ - 合并数字以形成一个大数字

    c++ - 当基类不是时,为什么派生类可以 move 构造?