我正在研究一个广泛使用 Eigen 的库的代码,并经常将Eigen::Matrix
个对象与我自己设计的NSObject
子类进行映射(vMAT_Array
)。使用库通常需要将矩阵编组到vMAT_Array
个实例中,以便可以传递它们等。
我有一个vMAT_cast
模板函数来处理这个:
template <typename EigenObjectType>
vMAT_Array * vMAT_cast(EigenObjectType matrix)
{
return Map<EigenObjectType>(matrix).matA;
}
此函数的问题在于它与 Eigen 的延迟评估语义无法正确交互。以下面的单元测试代码为例:
vMAT_Array * matM = vMAT_cast(VectorXd::LinSpaced(40, 1.0, 40.0).eval());
[matM reshape:vMAT_MakeSize(5, 8)];
Mat<double> M = matM;
Array<bool, Dynamic, Dynamic> sel = M.unaryExpr([](double elt) { return (int)elt % 3 == 0; }).cast<bool>();
vMAT_Array * vecN = vMAT_pick(matM, vMAT_cast(sel));
NSLog(@"%@", vecN.dump);
vMAT_Array * vecNv = vMAT_cast(VectorXd::LinSpaced(13, 3.0, 39.0).eval());
STAssertEqualObjects(vecN, vecNv, @"Logical indexing broken");
请注意对.eval()
的大多数参数的显式vMAT_cast
调用。这些是必要的,因为模板函数尝试(在编译时)使用 Eigen 的一个惰性表达式模板扩展到代码中,这会生成像这样的可爱错误消息:
/Users/Shared/Source/vMAT/vMATTests/EigenTests.mm:25:35: note: in instantiation of member function 'Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >::LinSpaced' requested here
vMAT_Array * matM = vMAT_cast(VectorXd::LinSpaced(40, 1.0, 40.0));
^
In file included from /Users/Shared/Source/vMAT/vMATTests/EigenTests.mm:11:
In file included from /Users/Shared/Source/vMAT/vMAT/vMAT.h:51:
/Users/Shared/Source/vMAT/vMAT/vMAT_Array.h:122:82: error: no member named 'data' in 'Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<double, true>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >'
data:[NSMutableData dataWithBytes:matrix.data()
~~~~~~ ^
我怀疑有一些模板会“迫使”MatrixBase::eval
发生,但我不了解它。谁能开导我?
答案 0 :(得分:2)
你可以在eigen / unsupported / Eigen / OpenGLSupport模块中找到这种模板kung-fu。在这里,您将找到OpenGL函数的包装器,它通过原始C指针获取向量和矩阵。关键是在这个测试中,我们检查表达式类型是否与OpenGL兼容:
bool IsGLCompatible = bool(XprType::Flags&LinearAccessBit)
&& bool(XprType::Flags&DirectAccessBit)
&& (XprType::IsVectorAtCompileTime || (XprType::Flags&RowMajorBit)==0)
LinearAccessBit意味着没有“步幅”,DirectAccessBit意味着有一个.data()可用。还有两个是显而易见的,可能与你的情况无关。
另一种选择,可能更简单,就是使用新的Ref&lt;&gt; devel分支的类。我参考doc了解这种方法的细节。