类型中的typedef与类中的typedef

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>可能希望利用现有的内存分配的FastAllocAlignedAlloc,但富需要知道如何使用这些两种接口,并且这样的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?除了风格选择之外还有什么理由吗?

Nic*_*las 7

我怀疑,因为traits类是internal,这是使用traits类的重点.也就是说,将这些东西保持在内部.这样一来,Matrix没有很多古怪的定义,这样,即使在其专用接口.

考虑示例中的枚举.那些"枚举"(又名:static constexprC++ 11之前的变量)看起来不像用户应该知道的任何东西.这是一个实现细节,因此应该隐藏它.


MatrixBase问题是CRTP问题.

看,Matrix将定义如下:

class Matrix : public MatrixBase<Matrix>
Run Code Online (Sandbox Code Playgroud)

这个部分定义会导致两件事情发生:

  1. 如果Matrix尚未声明为类类型,则它将成为可以引用和使用其名称的合法类.

  2. MatrixBase必须使用类型实例化模板Matrix.现在.

这里的问题是"现在",Matrix是一个不完整的类.编译器尚未进入该定义的主体,因此编译器对其内部结构一无所知.但MatrixBase必须立即实例化.

因此,MatrixBase不能使用它提供的类的任何内容Derived.如果其中Matrix有一些typedef,MatrixBase<Derived> 则无法看到它.

现在,成员函数MatrixBase<Derived>可以查看定义Derived,因为它们是在定义完整类之后定义的.即使这些函数是在类的范围内定义的.

但是你不能拥有MatrixBase访问属性的属性Derived.因此,特征是间接的.traits类可以使用基于不完整类型的特化来公开定义MatrixBase.