例如:
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);
有无什么方法可以简化这一大串?
迷茫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;
}
高洛峰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).