c++ - 特征中的 typedef 与类中的 typedef

标签 c++ templates eigen traits

出于教育目的,我正在查看 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>可能想利用现有的内存分配器 FastAllocAlignedAlloc , 但 Foo 需要知道如何与这两个接口(interface),因此 FooTraits<AlignedAlloc>::allocate()FooTraits<FastAlloc>::allocate()由用户定义,又由 Foo 使用.

但是,在这种情况下,我并不能轻易看出仅指定 Scalar 的问题。在每个派生类中,即有 Matrix定义 Matrix::Scalar在类主体中使用 typedef。使用 traits 类的优势是什么?是否只是为了保持代码整洁,即将每个类的所有相关属性存储在 traits 类中?

根据 Nicol Bolas 的回复进行编辑:我理解其中一些 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本身?除了文体选择之外还有什么原因吗?

最佳答案

我怀疑,因为特征类是 internal ,这就是使用特征类的意义所在。也就是说,将这些东西保留在内部。这样,Matrix没有很多奇怪的定义等,即使在其私有(private)接口(interface)中也是如此。

考虑示例中的枚举。那些“枚举”(又名:static constexpr C++11 之前的变量)看起来不像是用户应该知道的任何内容。这是一个实现细节,因此应该隐藏。


MatrixBase的问题是CRTP问题。

参见,Matrix会这样定义:

class Matrix : public MatrixBase<Matrix>

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

  1. 如果 Matrix还没有被声明为类类型,那么它就成为一个名称可以被引用和使用的合法类。

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

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

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

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

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

关于c++ - 特征中的 typedef 与类中的 typedef,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39132754/

相关文章:

c++ - 从 C++ 宏中删除额外的括号

c++ - 派生类的模板参数推导

C++ 模板友元运算符与另一个类似的运算符

c++ - 从 Eigen::Isometry3d 中提取旋转时出错?

采用 DenseBase 的模板函数中的 c++ 特征 block 操作

c++ - Windows CE 7.0 应用程序无法分步调试

c++ - 我不明白我的多类代码有什么问题(我最近开始使用 c++ 多类)

c# - 使用 SWIG 更改生成的 CS 函数中的返回类型

c++ - 如何使用模板专门化模板?

eigen - 使用 Eigen Vector3d 容器创建 PCL 点云