重载操作符 - c++中操作符重载需要写多种重复版本(引用与右值引用),有无方法可以简化
高洛峰
高洛峰 2017-04-17 15:38:40
0
2
823

例如:

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);

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

高洛峰
高洛峰

拥有18年软件开发和IT教学经验。曾任多家上市公司技术总监、架构师、项目经理、高级软件工程师等职务。 网络人气名人讲师,...

reply all(2)
迷茫

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;
}
小葫芦
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).

Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template