【发布时间】:2023-03-03 10:50:01
【问题描述】:
考虑一个简单的 int Wrapper 类,其中包含重载乘法 operator*= 和 operator*。对于“旧式”运算符重载,可以根据operator*= 定义operator*,甚至还有像Boost.Operators 这样的库以及@DanielFrey 的现代化身df.operators,可以为您减少样板文件。
但是,对于使用新的 C++11 constexpr 进行编译时计算,这种便利就消失了。 constexpr operator* 不能调用 operator*=,因为后者修改了它的(隐式)左参数。此外,还有no overloading on constexpr,因此在现有operator* 中添加额外的constexpr operator* 会导致重载解决方案不明确。
我目前的做法是:
#include <iostream>
struct Wrap
{
int value;
Wrap& operator*=(Wrap const& rhs)
{ value *= rhs.value; return *this; }
// need to comment this function because of overloading ambiguity with the constexpr version
// friend Wrap operator*(Wrap const& lhs, Wrap const& rhs)
// { return Wrap { lhs } *= rhs; }
friend constexpr Wrap operator*(Wrap const& lhs, Wrap const& rhs)
{ return { lhs.value * rhs.value }; }
};
constexpr Wrap factorial(int n)
{
return n? factorial(n - 1) * Wrap { n } : Wrap { 1 };
}
// want to be able to statically initialize these arrays
struct Hold
{
static constexpr Wrap Int[] = { factorial(0), factorial(1), factorial(2), factorial(3) };
};
int main()
{
std::cout << Hold::Int[3].value << "\n"; // 6
auto w = Wrap { 2 };
w *= Wrap { 3 };
std::cout << w.value << "\n"; // 6
}
Live output here。我的问题是:
-
operator*=和operator*中的乘法逻辑重复,而不是用operator*=表示的operator* - 因此,Boost.Operators 不再用于减少编写许多其他算术运算符的样板
问题:这是推荐的 C++11 方式,同时具有运行时 operator*= 和混合运行时/编译时 constexpr operator*? C++14 是否将这里的任何内容更改为例如减少逻辑重复?
更新:@AndyProwl 的回答被接受为惯用语,但根据@DyP 的建议,在 C++11 中,可以减少逻辑重复,但代价是额外的任务和违反直觉的风格
// define operator*= in terms of operator*
Wrap& operator*=(Wrap const& rhs)
{ *this = *this * rhs; return *this; }
【问题讨论】:
-
如果可以是
constexpr,“常规”重载有什么用? IIRCconstexpr将在非constexpr上下文中优雅地降级为运行时执行。 -
@sehe 你不能有
constexpr operator*=,所以constexpr operator*不能调用它,而是需要复制提取字段等的逻辑。 -
啊,我开始看到你真正的问题了。 不是关于有非
constexpr重载(你不需要它们!)而是关于不能共享代码,因为*=不能constexpr。好在我已经真诚地 +1 了 :) -
@DyP 你的意思是
*this = *this * rhs; return *this;作为operator*的正文?我觉得这样效率不高,但也许编译器会优化并生成原始代码? -
(作为
operator *=的正文,我猜这是一个错字?)你包装的类型无论如何都需要一个constexpr复制ctor,所以这个分配不应该很复杂(没有内存分配等)。这意味着move也可能不会比copy有很多优势,但编译器优化这个赋值应该不难,因为它不应该有副作用。
标签: c++ c++11 operator-overloading constexpr c++14