Moo*_*ing 9 c++ templates traits eigen
我正在查看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
};
};
}
Run Code Online (Sandbox Code Playgroud)
现在,我理解traits是一种扩展现有类的方法,您不希望使用与某些新代码相关的额外信息来修改这些类.例如,类模板的用户Foo<class TAllocator>
可能希望利用现有的内存分配的FastAlloc
和AlignedAlloc
,但富需要知道如何使用这些两种接口,并且这样的FooTraits<AlignedAlloc>::allocate()
和FooTraits<FastAlloc>::allocate()
由用户,而这又是通过使用定义Foo
.
但是,在这种情况下,我不容易Scalar
在每个派生类中指定问题,即在类体中使用typedef进行Matrix
定义Matrix::Scalar
.使用特质类的优点是什么?它只是为了保持代码干净,即在traits类中存储每个类的所有相关属性?
根据Nicol Bolas的回复进行编辑:我理解其中一些typedef可能需要保持"内部",即不应该向用户公开,这将解释traits类.这似乎是有道理的,但一些类型定义,比如Scalar
,是提供给外部世界,通过在基类的一个typedef Matrix
:
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;
Run Code Online (Sandbox Code Playgroud)
这让我们回到原来的问题:为什么它本身Scalar
不仅仅是一个typedef Matrix
?除了风格选择之外还有什么理由吗?
我怀疑,因为traits类是internal
,这是使用traits类的重点.也就是说,将这些东西保持在内部.这样一来,Matrix
没有很多古怪的定义,这样,即使在其专用接口.
考虑示例中的枚举.那些"枚举"(又名:static constexpr
C++ 11之前的变量)看起来不像用户应该知道的任何东西.这是一个实现细节,因此应该隐藏它.
MatrixBase
问题是CRTP问题.
看,Matrix
将定义如下:
class Matrix : public MatrixBase<Matrix>
Run Code Online (Sandbox Code Playgroud)
这个部分定义会导致两件事情发生:
如果Matrix
尚未声明为类类型,则它将成为可以引用和使用其名称的合法类.
MatrixBase
必须使用类型实例化模板Matrix
.现在.
这里的问题是"现在",Matrix
是一个不完整的类.编译器尚未进入该定义的主体,因此编译器对其内部结构一无所知.但MatrixBase
必须立即实例化.
因此,MatrixBase
不能使用它提供的类的任何内容Derived
.如果其中Matrix
有一些typedef,MatrixBase<Derived>
则无法看到它.
现在,成员函数MatrixBase<Derived>
可以查看定义Derived
,因为它们是在定义完整类之后定义的.即使这些函数是在类的范围内定义的.
但是你不能拥有MatrixBase
访问属性的属性Derived
.因此,特征是间接的.traits类可以使用基于不完整类型的特化来公开定义MatrixBase
.