【问题标题】:Using move semantics and perfect forwarding to implement a 'lazy' operator+使用移动语义和完美转发来实现“惰性”运算符+
【发布时间】:2014-12-22 03:51:11
【问题描述】:

我正在尝试写一个

friend T operator+( lhs, rhs){
};

现在,我想尽可能避免建造临时建筑。

例如:

  1. 如果lhsrhs 都是const T&,则operator+ 应该从lhs 创建一个temp 复制构造,然后将temp += rhs; 复制到它,最后是return std::move(temp)
  2. 如果lhsT&&,那么我想直接将rhslhs += rhs; 相加,然后再将return std::move(lhs) 相加。这种情况避免了(A+B)+C 中的复制构造,因为在表达式之外不需要(A+B) 的输出。请注意,我们可能必须使用temp(std::move(lhs)) 才能为案例 1 和案例 2 提供一个通用代码。
  3. rhslhsrhs 都是T&& 时,其他两种情况也是如此。

通过编写四个重载,我设法做到了这一点。现在,我读到可以利用模板和forward 来减少重载的数量,甚至可以将其写入一个模板函数中。我很难理解如何。

看来我需要

template<typename R, typename S, typename T>
R operator+(S&& lhs, T&& rhs){
   // ...
};

但是我尝试过的内容不起作用。

还有一个我可能需要处理的问题。如果不是operator+,我们需要operator-operator/ 方法的主体,它不一定在所有情况下都相似。在A/B 中,如果AT&amp;&amp;,我们可以A /= B。但如果BT&amp;&amp;,那么我们可能需要使用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


【解决方案1】:

编写一个名为sum 的函数。 sum 有 3 个重载:lhs&amp;&amp;, rhs const&amp;lhs const&amp;, rhs&amp;&amp;, ...——... 很重要,因为它使它成为最差的匹配,消除了歧义。最后是const&amp; lhs, const&amp; rhs

然后template&lt;lhs, rhs&gt; auto operator+(lhs&amp;&amp;,rhs&amp;&amp;)-&gt;decltype完美转发到sum

一旦你完成了这项工作,我们就可以继续前进。我们可以为每个运算符重新实现它,或者提升一个抽象级别。

你有一个变异的二元运算(+= 等)和一个反对称变换(大多数情况下是 noop,除法是逆运算——除法的二元运算是 *= 顺便说一句)。将它们传递给像 sum 这样重载的调度程序。

为这两个使用函数对象,重写sum 函数以获取increase_mat{}noop{} 应该很容易。

【讨论】:

  • 您的答案已被看到。现在把我的头绕在它周围。
  • @dyp 有什么额外的动作? std::move 不动,也不回?仅在移动后绑定到值...啊,我明白了:const&amp; 无需移动即可移动?
  • @dyp 二元运算符是+= 不是+
  • 我认为这是我的方法的一个特殊性。如果你依赖副作用,你就不会有这个问题(而且这也不是真正的问题)。没关系。
猜你喜欢
  • 2014-09-04
  • 1970-01-01
  • 1970-01-01
  • 2013-04-14
  • 1970-01-01
  • 1970-01-01
  • 2015-09-25
  • 1970-01-01
  • 2011-11-19
相关资源
最近更新 更多