我正在查看Eigen源代码,以便进行教育目的。我注意到,在继承结构中的每个具体类模板X
中,都定义了一个internal::traits<X>
。在Matrix.h中可以找到一个典型示例:
namespace internal {
template<typename _Scalar, int _Rows, int _Cols, int _Options, int _MaxRows, int _MaxCols>
struct traits<Matrix<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols> >
{
typedef _Scalar Scalar;
typedef Dense StorageKind;
typedef DenseIndex Index;
typedef MatrixXpr XprKind;
enum {
RowsAtCompileTime = _Rows,
ColsAtCompileTime = _Cols,
MaxRowsAtCompileTime = _MaxRows,
MaxColsAtCompileTime = _MaxCols,
Flags = compute_matrix_flags<_Scalar, _Rows, _Cols, _Options, _MaxRows, _MaxCols>::ret,
CoeffReadCost = NumTraits<Scalar>::ReadCost,
Options = _Options,
InnerStrideAtCompileTime = 1,
OuterStrideAtCompileTime = (Options&RowMajor) ? ColsAtCompileTime : RowsAtCompileTime
};
};
}
现在我理解traits是一种扩展现有类的方式,您不想通过额外信息修改与某些新代码相关的类。例如,使用类模板
Foo<class TAllocator>
的用户可能希望利用现有的内存分配器FastAlloc
和AlignedAlloc
,但Foo需要知道如何与这两个接口,并且因此用户定义了FooTraits<AlignedAlloc>::allocate()
和FooTraits<FastAlloc>::allocate()
,这反过来又被Foo
所使用。
然而,在这种情况下,我并不容易看出只需在每个派生类中指定Scalar
的问题,即在类体中使用typedef定义Matrix::Scalar
。在这里使用traits类的优点是什么?它只是为了保持代码的整洁吗,即将每个类的所有相关属性存储在traits类中吗?
根据Nicol Bolas的回应进行编辑:我理解其中一些typedef可能需要保持“内部”,即不应向用户公开,这就解释了traits类。这似乎是有道理的,但是其中一些typedef,例如Scalar
,是通过Matrix
基类中的typedef可供外界使用的:
template<typename Derived> class MatrixBase
: public DenseBase<Derived>
{
public:
typedef MatrixBase StorageBaseType;
typedef typename internal::traits<Derived>::StorageKind StorageKind;
typedef typename internal::traits<Derived>::Index Index;
typedef typename internal::traits<Derived>::Scalar Scalar;
typedef typename internal::packet_traits<Scalar>::type PacketScalar;
typedef typename NumTraits<Scalar>::Real RealScalar;
这让我们回到最初的问题:为什么
Scalar
不只是Matrix
本身的typedef?除了风格选择之外,还有其他原因吗?
Matrix
继承自MatrixBase
类,该类公开定义了一些这些typedefs,例如Scalar
,这使我们回到了起点 - 为什么不从一开始就在Matrix
中定义Scalar
呢? - Moos Hueting