search

Home  >  Q&A  >  body text

重载操作符 - c++中操作符重载需要写多种重复版本(引用与右值引用),有无方法可以简化

例如:

mat33 operator +(mat33& m1, mat33& m2);
mat33 operator -(mat33& m1, mat33& m2);
mat33 operator +(mat33&& m1, mat33&& m2);
mat33 operator -(mat33&& m1, mat33&& m2);
mat33 operator +(mat33&& m1, mat33& m2);
mat33 operator -(mat33&& m1, mat33& m2);
mat33 operator +(mat33& m1, mat33&& m2);
mat33 operator -(mat33& m1, mat33&& m2);

有无什么方法可以简化这一大串?

高洛峰高洛峰2787 days ago814

reply all(2)I'll reply

  • 迷茫

    迷茫2017-04-17 15:40:40

    If you want to reduce the number of declarations, there is a way, simplifying the code seems impossible. Following the idea of ​​your declaration, &&,&& and &&,& can delegate work to &,&&. This way the code is not complicated and there is no duplication.

    At least two implementations are required here, one that moves data and one that does not. Mobile data is divided into lhs and rhs. At the same time, ADL must be taken into consideration. Implementing this requires declaring at least three overloads. Using templates can reduce the declaration to two:

    template <class T>
    std::enable_if_t<std::is_convertible<T, mat33>::value, mat33>
    operator+(T &&, const mat33 &) {
      if (std::is_rvalue_reference<T &&>::value && !std::is_const<T>::value) {
        std::cout << "move from lhs" << std::endl;
      } else {
        std::cout << "no move" << std::endl;
      }
      return {};
    }
    
    template <class T>
    inline mat33 operator+(T &&lhs, mat33 &&rhs) {
      std::cout << "rhs -> lhs, ";
      return std::move(rhs)+lhs;
    }
    

    PS: After c++17, you can use constexpr if to implement static branching. Compilers before c++17 can usually complete such optimizations.

    Test code:

    #include <utility>
    #include <type_traits>
    #include <iostream>
    
    namespace detail {
    
    struct mat33 {};
    
    template <class T>
    std::enable_if_t<std::is_convertible<T, mat33>::value, mat33>
    operator+(T &&, const mat33 &) {
      if (std::is_rvalue_reference<T &&>::value && !std::is_const<T>::value) {
        std::cout << "move from lhs" << std::endl;
      } else {
        std::cout << "no move" << std::endl;
      }
    }
    
    template <class T>
    inline mat33 operator+(T &&lhs, mat33 &&rhs) {
      std::cout << "rhs -> lhs, ";
      return std::move(rhs)+lhs;
    }
    
    } // namespace detail
    
    
    int main() {
      detail::mat33 a, b;
      const detail::mat33 ca, cb;
      
      // move from lhs
      std::move(a)+b;
      std::move(a)+cb;
      
      // rhs -> lhs, move from lhs
      a+std::move(b);
      ca+std::move(b);
    
      // no move
      a+b;
    
      ca+cb;
      std::move(ca)+cb;
      ca+std::move(cb);
    
      a+cb;
      ca+b;
      std::move(ca) + b;
      a + std::move(cb);
    
      return 0;
    }

    reply
    0
  • 高洛峰

    高洛峰2017-04-17 15:40:40

    mat33 operator +(const mat33& m1, const mat33& m2);
    mat33 operator -(const mat33& m1, const mat33& m2);
    

    It’s done. . .
    const & can match all references (lvalue, rvalue, constant lvalue, constant rvalue).

    reply
    0
  • Cancelreply