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

浏览:26日期:2023-03-22

问题描述

例如:

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

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

问题解答

回答1:

如果你想要减少声明的次数,那是有办法的,简化代码似乎不可能。按照你的声明思路,&&,&&和&&,&可以将工作代理给&,&&。这样代码不复杂,也没有重复。

这里至少需要两个实现,其中一个移动数据,另一个不移动数据。移动数据分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 detailint 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;}回答2:

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

不就搞定了。。。const & 能匹配所有引用(左值、右值、常量左值、常量右值)。

相关文章: