有没有办法在模板函数参数上“强制”MatrixBase :: eval?

时间:2013-04-17 15:18:43

标签: templates objective-c++ eigen vmat

我正在研究一个广泛使用 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发生,但我不了解它。谁能开导我?

1 个答案:

答案 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了解这种方法的细节。