【发布时间】:2014-12-22 03:51:11
【问题描述】:
我正在尝试写一个
friend T operator+( lhs, rhs){
};
现在,我想尽可能避免建造临时建筑。
例如:
- 如果
lhs和rhs都是const T&,则operator+应该从lhs创建一个temp复制构造,然后将temp += rhs;复制到它,最后是return std::move(temp)。 - 如果
lhs是T&&,那么我想直接将rhs与lhs += rhs;相加,然后再将return std::move(lhs)相加。这种情况避免了(A+B)+C中的复制构造,因为在表达式之外不需要(A+B)的输出。请注意,我们可能必须使用temp(std::move(lhs))才能为案例 1 和案例 2 提供一个通用代码。 - 当
rhs或lhs和rhs都是T&&时,其他两种情况也是如此。
通过编写四个重载,我设法做到了这一点。现在,我读到可以利用模板和forward 来减少重载的数量,甚至可以将其写入一个模板函数中。我很难理解如何。
看来我需要
template<typename R, typename S, typename T>
R operator+(S&& lhs, T&& rhs){
// ...
};
但是我尝试过的内容不起作用。
还有一个我可能需要处理的问题。如果不是operator+,我们需要operator- 或operator/ 方法的主体,它不一定在所有情况下都相似。在A/B 中,如果A 是T&&,我们可以A /= B。但如果B 是T&&,那么我们可能需要使用B.reciprocal() *= A。所以,我想我还需要一种方法来知道在模板中输入了哪种情况。
注意:我的乘法是可交换的(矩阵中的组件乘法)。
您能否就如何解决这个问题提供一些 cmets 和想法?
给自己和下一位读者的注意事项:link 是关于使用表达式模板的一些阅读。
【问题讨论】:
-
我认为对于真正的惰性求值,你将不得不使用表达式模板。
-
我不确定这种概括程度是否合理。移动语义是关于重的、拥有资源的对象。除法和减法是关于数字的。
-
@KerrekSB 使用一些抽象。我从来没有说过
A,B,C是数字。就我而言,它们实际上是矩阵,而且它们将是大矩阵。 -
如果您的运算符是可交换的,则可以尝试通过重新排序参数来应用一种减少样板文件的技术,以便第一个始终是右值:coliru.stacked-crooked.com/a/14d811e4d7e9297b(但这会增加必要的移动量,因为右值可能是在一个函数中创建的,因此必须移出)。
-
注意:
return temp;会移动,你不需要return std::move(temp);(除非返回变量是左值引用,那么你可能不应该尝试移动它)。您已经注意到,交换性并不适用于所有运算符……对于矩阵,它甚至不适用于*。矩阵乘法和除法结果可能与任一操作数的大小不同,因此无法重用操作数。即使对于方阵,operator*=也是按照*然后=实现的,因为在计算过程中需要重复左侧。
标签: c++ lazy-evaluation move-semantics perfect-forwarding