在使用Eigen编程时,到处是Curiously recurring template pattern,那么,我们如何知道一个矩阵中存的是double型变量还是float型的变量呢?
有人会说, MatrixXd中存的就是double型变量MatrixXf中存的是float型变量啊!
我是无耻的插队者:不了解Curiously recurring template pattern的可以看我之前的文章:http://cherishlc.iteye.com/blog/1994276
可是,如果一个泛型函数是如下定义的,我们如何知道X中存的是什么类型的变量呢?
class="C++" name="code">template <typename Derived> void cov(const MatrixBase<Derived>& X){}
先说一下这样写的好处:
- 1、通用性强,X既可以是MatrixXd类型的,也可以是MatrixXf类型的,甚至是矩阵的一个子块m1.block(0,0,10,10)的 或者表达式 m1+m2 (假设m1,m2为MatrixXd类型的)
- 2、速度快(表达式类型不用先进行运算,存为Matrix了)
但是,事物都有其两面性。。。
问题来了:如果再写函数的过程中,我们需要声明一个临时变量,与X中存储的元素类型相同,该如何声明?
答案很简单,Eigen在MatrixBase类(事实上是近乎所有类)中为我们定义了这些类型,
类型列表如下:
- Scalar: 矩阵中存储的类型
- Index: 矩阵下标的类型,貌似为unsigned int型的
- PlainObject: 表达式对应的矩阵类型, 比如m1+m2对应的PlainObject为 m1的类型,即decltype(m1)
使用的时候,用如下语句可以声明一个变量s:
typename Derived::Scalar s;
好了,最后来膜拜一下PlainObject的定义:
typedef Matrix<typename internal::traits<Derived>::Scalar, internal::traits<Derived>::RowsAtCompileTime, internal::traits<Derived>::ColsAtCompileTime, AutoAlign | (internal::traits<Derived>::Flags&RowMajorBit ? RowMajor : ColMajor), internal::traits<Derived>::MaxRowsAtCompileTime, internal::traits<Derived>::MaxColsAtCompileTime > PlainObject
还有些简单的:
typedef typename internal::traits<Derived>::Index Index;
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
可能有些人还会有疑问,为何是internal::traits<Derived>::Scalar 而不是Derived::Scalar(事实上我们用的时候可以这么用,但是在写Eigen库的过程中不行)!!原因是在编写Eigen库的过程中,类型相互引用,会产生类型未定义的问题(大致如此,描述可能不准确),这样的问题,我们作为库的使用者是不会遇到的
摘录Eigen官方文档如下:
引用Let us now explain the internal::traits here. The internal::scalar_sum_op class takes one template parameter: the type of the numbers to handle. Here of course we want to pass the scalar type (a.k.a. numeric type) of VectorXf, which is float. How do we determine which is the scalar type of Derived ? Throughout Eigen, all matrix and
expression types define a typedef Scalar which gives its scalar type. For example, VectorXf::Scalar is a typedef for float. So here, if life was easy, we could find the numeric type of Derived as just
typename Derived::Scalar
Unfortunately, we
can't do that here, as the compiler would complain that the type Derived
hasn't yet been defined. So we use a workaround: in src/Core/util/ForwardDeclarations.h, we declared (not defined!) all our subclasses, like Matrix, and we also declared the following class template:
template<typename T> struct internal::traits;
In src/Core/Matrix.h, right before the definition of class Matrix, we define a partial specialization of internal::traits for T=Matrix<any template parameters>. In this specialization of internal::traits, we define the Scalar typedef. So when we actually define Matrix, it is legal to refer to "typename internal::traits\<Matrix\>::Scalar".
Matrix类官方文档:
http://eigen.tuxfamily.org/dox/classEigen_1_1Matrix.html
MatrixBase类官方文档:
http://eigen.tuxfamily.org/dox/classEigen_1_1MatrixBase.html#ac33495a0e3788e5951670c392b44d9ad
编写Eigen的泛型函数:
http://eigen.tuxfamily.org/dox/TopicFunctionTakingEigenTypes.html
关于internal::traits的,这篇对理解Eigen架构很有帮助:
http://eigen.tuxfamily.org/dox/TopicInsideEigenExample.html