首頁  >  問答  >  主體

重载操作符 - 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);

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

高洛峰高洛峰2765 天前793

全部回覆(2)我來回復

  • 迷茫

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

    如果你想要減少聲明的次數,那是有辦法的,簡化程式碼似乎不可能。依照你的聲明思路,&&,&&&&,&可以將工作代理給&,&&。這樣程式碼不複雜,也沒有重複。

    這裡至少需要兩個實現,其中一個移動數據,另一個不移動數據。移動資料分lhs和rhs。同時也要兼顧ADL。實現這些至少需要聲明三個重載。用模板可以將聲明減少到兩個:

    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: c++17後可以用constexpr if實作靜態分枝。 c++17之前編譯器也通常可以完成這樣的最佳化。

    測試程式碼:

    #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;
    }

    回覆
    0
  • 高洛峰

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

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

    不就搞定了。 。 。
    const & 能符合所有引用(左值、右值、常數左值、常數右值)。

    回覆
    0
  • 取消回覆