例如:
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
如果你想要减少声明的次数,那是有办法的,简化代码似乎不可能。按照你的声明思路,&&,&&
和&&,&
可以将工作代理给&,&&
。这样代码不复杂,也没有重复。
这里至少需要两个实现,其中一个移动数据,另一个不移动数据。移动数据分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;
}
高洛峰2017-04-17 15:40:40
mat33 operator +(const mat33& m1, const mat33& m2);
mat33 operator -(const mat33& m1, const mat33& m2);
不就搞定了。。。
const & 能匹配所有引用(左值、右值、常量左值、常量右值)。