使用Eigen::Ref<>传递矩阵行作为左值引用的问题
解决Eigen中传递
.row(i)作为左值引用的性能问题 问题背景
现有代码可正常运行,但性能分析显示Eigen::internal::dense_assignment_loop::run占用44.8%的耗时,推测是循环中临时变量tmp的拷贝操作导致:
for ( index_type i = 0; i <= n; ++i ) { de_casteljau( tmp, B_v[ i ], v ); temp_cp.row( i ) = tmp; }
尝试直接传递temp_cp.row(i)以消除拷贝,修改后的代码如下:
for ( index_type i = 0; i <= n; ++i ) { de_casteljau( temp_cp.row( i ), B_v[ i ], v ); }
编译错误情况
clang报错提示无法匹配函数调用,原因是de_casteljau的第一个参数要求左值,但.row(i)返回的是临时Block对象(右值):
error: no matching function for call to 'de_casteljau' note: candidate function [with Derived1 = Eigen::Block<Eigen::Matrix<double, -1, 3>, 1, 3>, Derived2 = Eigen::Map<Eigen::Matrix<double, -1, 3>, 0, Eigen::Stride<1, -1>>] not viable: expects an lvalue for 1st argument 27 | void de_casteljau(Eigen::MatrixBase<Derived1> &p, const Eigen::MatrixBase<Derived2> &cp, const typename Derived2::Scalar &t)
尝试将de_casteljau的函数声明改为使用Eigen::Ref,但写法错误导致新的编译错误:
template < typename Derived1, typename Derived2 > void de_casteljau( Eigen::Ref < Eigen::MatrixBase < Derived1 > > p, const Eigen::MatrixBase < Derived2 > & cp, const typename Derived2::Scalar & t )
错误信息:
error: no matching function for call to 'de_casteljau' note: candidate template ignored: could not match 'Ref' against 'Matrix' 27 | void de_casteljau(Eigen::Ref < Eigen::MatrixBase<Derived1> > p, const Eigen::MatrixBase<Derived2> &cp, const typename Derived2::Scalar &t)
要求在不修改de_casteljau现有调用点的前提下解决问题。
正确解决方案
将de_casteljau的第一个参数改为Eigen::Ref<Derived1>(而非Eigen::Ref<Eigen::MatrixBase<Derived1>>),让模板参数直接推导目标类型,同时兼容左值和右值表达式:
修改后的函数声明
template < typename Derived1, typename Derived2 > void de_casteljau( Eigen::Ref<Derived1> p, const Eigen::MatrixBase<Derived2> & cp, const typename Derived2::Scalar & t )
函数实现保持不变
{ // do some checks on incoming matrix dimensions assert( p.cols() == cp.cols() ); Eigen::Matrix < typename Derived2::Scalar, Eigen::Dynamic, Eigen::Dynamic > Q( cp ); typename Derived2::Scalar oneminust( 1 - t ); typename Derived2::Index k, i; for ( k = 1; k < Q.rows(); ++k ) { for ( i = 0; i < Q.rows() - k; ++i ) { Q.row( i ) = oneminust * Q.row( i ) + t * Q.row( i + 1 ); } } p = Q.row( 0 ); }
原理说明
Eigen::Ref<Derived1>可以绑定任意可赋值的Eigen表达式,包括左值(如point_type对象)和临时右值(如.row(i)返回的Block对象),无需修改原有调用点。- 这种写法既消除了临时变量
tmp的拷贝操作,又保持了代码的兼容性,完全匹配性能优化的需求。
内容的提问来源于stack exchange,提问作者Rob McDonald
相关产品推荐
相关产品推荐

