【问题标题】:Pass v.cwiseAbs() to a function that accept Ref<VectorXd>将 v.cwiseAbs() 传递给接受 Ref<VectorXd> 的函数
【发布时间】:2020-02-17 00:46:17
【问题描述】:

以下似乎不起作用。

void Foo(Ref<VectorXd> v) {
  // modifies v
}

Eigen::VectorXd v;
Foo(v.cwiseAbs());

出现以下错误信息

错误:无法用 Derived = Eigen::ArrayWrapper, -1, 1, true>, -1, 1, false> 转换 'Eigen::ArrayBase::cwiseAbs() const >; Eigen::ArrayBase::CwiseAbsReturnType = Eigen::CwiseUnaryOp, const Eigen::ArrayWrapper, -1, 1, true>, -1, 1, false> > >; typename Eigen::internal::traits::Scalar = double' from 'const CwiseAbsReturnType {aka const Eigen::CwiseUnaryOp, const Eigen::ArrayWrapper, -1, 1, true>, -1, 1, false> > >} ' 到 'Eigen::Ref >'

任何建议为什么以及如何解决?

【问题讨论】:

  • 你希望它做什么?

标签: eigen eigen3


【解决方案1】:

这不起作用,因为需要两个额外的const 限定符才能匹配.cwiseAbs() 返回的表达式。这是有道理的,因为不可能通过以引用形式接受此参数的函数来修改v.cwiseAbs() 的结果。以下代码编译:

void Foo(const Ref<const VectorXd>& v) {
  std::cout << v << std::endl;
}

int main() {
  Eigen::VectorXd v(3);
  v << 1,-2,3;
  Foo(v.cwiseAbs());
}

但是,通过此修改,不允许在Foo() 内修改v

最简单的解决方案可能是删除Ref&lt;&gt; 并使用

 Foo(VectorXd v) {...}

相反。这会生成一个本地副本,但这在性能方面应该不是问题,此外,如果要在Foo() 中修改v,无论如何都无法避免任何副本。如果Ref 保留在Foo 的签名中,则可以复制v.cwiseAbs() 并使用该副本调用Foo()

void Foo(Ref<VectorXd> v) {...}
...
Eigen::VectorXd w = v.cwiseAbs();
Foo(w);

正如@chtz 所建议的,C++11 提供的替代方案是

void Foo(VectorXd&& v) {...}

虽然这允许在Foo() 中修改v,但使用它可能有些危险,因为在Foo() 中只更改了一个临时值。在Foo() 中对v 的修改不会改变main() 中的v

【讨论】:

  • 建议使用const Ref&lt;const VectorXd&gt; &amp;v 而不是const Ref&lt;const VectorXd&gt; v(因为Ref&lt;const X&gt; 可以保存一个临时的,这使得复制成本很高,尽管在实践中这通常(希望)被优化掉)。而使用 C++11 的替代方案是 void Foo(VectorXd&amp;&amp; v),这将允许修改 v,但通常只是编辑一个临时的(所以要小心使用它)。
  • 感谢您的见解! Foo(VectorXd v) 是一个好的解决方案吗?我想在这种情况下它很好,因为它像上面的解决方案一样制作一个副本?对于其他情况,例如v.block() 会复制一份,而Ref&lt;&gt; 不会?有什么特别的理由支持Foo(VectorXd&amp;&amp;) 而不是Foo(VectorXd)?谢谢!
  • 我认为Foo(VectorXd) 是去这里的方式。通常,引用对于 (a) 避免复制从而提高性能和/或 (b) 在退出函数后将参数的修改版本 (v) 返回到主代码很有用。由于此处不允许 (b) 并且 (a) 不太可能成为关键点,因此我将放弃 Ref 并使用 Foo(VectorXd v)。不确定Foo(VectorXd&amp;&amp;) 的可能优势,但我认为它可能会更快一些,因为它使用临时而不是将数据复制到新对象。恕我直言,不值得复杂的语法。
  • @bill 你真正想要什么行为?为什么要修改v?如果它不会对调用者产生副作用,您可以传递 const MatrixBase&lt;Derived&gt;&amp; 并将其复制到局部变量。不过,按值传递确实具有您可以显式地std::move 函数不再需要的变量的优势。
  • 知道了。感谢您的见解!真正的问题是要有一个分位数函数 foo(我能想到的最好的就是用 std::nth_element 修改输入),它的主要用法是 foo(v.abs()) 或 foo(v.col(j ).head(n).abs()).
猜你喜欢
  • 2020-04-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-07-29
  • 2018-03-12
  • 2014-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多