【问题标题】:CRTP: Determine derived class type in base class function to allow code reuseCRTP:在基类函数中确定派生类类型以允许代码重用
【发布时间】:2020-08-22 09:20:11
【问题描述】:

假设我有一个用于矩阵的 CRTP 模板类

template<class T, class Derived>
class MatrixBase{
private:
    //...

public:
    Derived some_function(const Derived &other){
          Derived& self = (Derived&)*this; // In my application I cant use static_cast.

          // Some calculations..., which will determine the below 
          // defined variables "some_number_of_rows" and "some_number_of_cols"

          // If Derived = DynamicMatrix<T>, then result should be declared as:
          DynamicMatrix<T> result(some_number_of_rows, some_number_of_cols);

          // while if Derived = StaticMatrix<T, Rows, Cols>, then result should be declared as:
          StaticMatrix<T, some_number_of_rows, some_number_of_cols> result;

          // Perform some more calculations...

          return result;
    }
};

template<class T>
class DynamicMatrix{
private:
     size_t n_rows, n_cols;
     T *data;
public:
     DynamicMatrix(const size_t n_rows, const size_t n_cols);
     // ...
};

template<class T, int Rows, int Cols>
class StaticMatrix{
private:
     size_t n_rows = Rows, n_cols = Cols;
     T data[Rows * Cols];
public:
     StaticMatrix() {}
     // ...
};

如何检查MatrixBase::some_function(const Derived &amp;other) 中的派生类类型以在两个派生类中使用此基函数?,从而避免在这些类中分别重新定义/覆盖/代码重复。在这种情况下,基本上只有result 矩阵的声明需要我检查派生类类型,因为声明是不同的,具体取决于它是固定大小的矩阵还是动态矩阵。也欢迎使用除类型检查之外的其他解决方案。

注意:由于我的应用程序的性质,我无法使用标准功能。

编辑:示例函数中的some_number_of_rowssome_number_of_cols 通常不是constexpr,因为它们取决于对象矩阵的函数和大小。例如,对于 transpose 函数,结果的维度必须为 &lt;Derived.n_cols, Derived.n_rows,而对于按列的点积,则为 &lt;1, Derived.n_cols&gt;

【问题讨论】:

  • some_number_of_rowssome_number_of_cols 来自哪里?来自&amp;other?
  • “一些计算...,这将确定 [..] some_number_of_rowssome_number_of_cols。对于StaticMatrix,这些应该是constexprDynamicMatrix 怎么样?
  • 哦,是的,我的错。

标签: c++ templates crtp


【解决方案1】:

这是一个具有挑战性的问题。基本上,some_number_of_rowssome_number_of_cols 必须StaticMatrix的情况下是constexpr,而不能DynamicMatrix的情况下是constexpr。 p>

一种解决方案是将新矩阵的创建委托给派生类。它将以constexpr 或不constexpr 进行大小计算,以适合它的为准。

另一种是在 CRTP 类中进行大小计算两次,一次为constexpr,一次为非constexpr,并将两个结果传递给派生对象创建函数:constexpr 作为模板参数传递, 和非constexpr 作为常规参数。创建函数专门用于静态和动态矩阵。静态版本忽略非constexpr参数,反之亦然。

【讨论】:

    【解决方案2】:

    据我了解,您可以在Derived 中添加那些工厂方法:

    如果some_number_of_rowssome_number_of_cols 在这两种情况下都可以是 constexpr(以满足更受​​约束的Derived),您可以执行以下操作:

    template<class T>
    class DynamicMatrix
    {
      // ...
      template <std::size_t Row, std::size_t Col>
      static DynamicMatrix<T> Create() { return DynamicMatrix(Row, Col); }
    };
    
    template <class T, int Rows, int Cols>
    class StaticMatrix{
      // ...
      template <std::size_t Row, std::size_t Col>
      static StaticMatrix<T, Row, Col> Create() { return {}; }
    };
    

    auto result = Derived::Create<some_number_of_rows, some_number_of_cols>();
    

    否则,您也必须将该计算转移到派生函数中:

    template<class T>
    class DynamicMatrix
    {
      // ...
      DynamicMatrix<T> CreateEmptyTransposed() const { return DynamicMatrix(n_cols, n_rows); }
    };
    
    template <class T, int Rows, int Cols>
    class StaticMatrix{
      // ...
      StaticMatrix<T, Cols, Row> CreateEmptyTransposed() const { return {}; }
    };
    

    auto result = self.CreateEmptyTransposed();
    

    【讨论】:

    • Derived::Create&lt;some_number_of_rows, some_number_of_cols&gt;(); 在动态矩阵的情况下是无效的,因为维度不是constexpr(并且它们在内部被忽略的事实并不使其合法)。
    • @n.'pronouns'm.:我在解释中放置了一个“如果”,因为不清楚some_number_of_rowssome_number_of_cols 是否为 constexpr。并在没有的情况下提供“解决方案”(带有转置示例)。
    • 它们是静态矩阵的 constexpr 而不是动态矩阵的 constexpr(显然)。
    • @n.'pronouns'm.: OP 可能想用sizeof T 创建方阵;)它确实更有可能取决于Derived 的维度。我希望我的措辞足够清楚:/
    猜你喜欢
    • 1970-01-01
    • 2021-10-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-27
    • 1970-01-01
    • 2021-09-10
    • 1970-01-01
    相关资源
    最近更新 更多