CRTP: determina il tipo di classe derivata nella funzione della classe di base per consentire il riutilizzo del codice

Aug 22 2020

Diciamo che ho una classe modello CRTP per matrici

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() {}
     // ...
};

Come posso verificare il tipo di classe derivata MatrixBase::some_function(const Derived &other)per utilizzare questa funzione di base in entrambe le classi derivate? , impedendo la necessità di ridefinire/sovrascrivere/duplicare il codice in queste classi separatamente. In questo caso è fondamentalmente solo la dichiarazione della resultmatrice che mi richiede di verificare il tipo di classe Derived, poiché la dichiarazione è diversa a seconda che si tratti di una matrice a dimensione fissa o dinamica. Sono benvenute anche altre soluzioni oltre al controllo del tipo.

NOTA : non posso utilizzare le funzionalità standard a causa della natura della mia applicazione.

EDIT : la funzione some_number_of_rowse some_number_of_colsnella funzione di esempio non sono generalmente constexpr, poiché dipendono dalla funzione e dalla dimensione della matrice dell'oggetto. Ad esempio, per una transposefunzione, il risultato dovrebbe avere dimensione <Derived.n_cols, Derived.n_rowse, nel caso di un prodotto scalare per colonna, <1, Derived.n_cols>.

Risposte

1 n.'pronouns'm. Aug 22 2020 at 18:24

Questo è un problema impegnativo. Fondamentalmente, some_number_of_rowse some_number_of_cols deve essere constexprin caso di StaticMatrixe non può essere constexprin caso di DynamicMatrix.

Una soluzione consiste nel delegare la creazione di nuove matrici alla classe derivata. Eseguirà il calcolo delle dimensioni come constexpro meno constexpr, a seconda di quale funzioni per esso.

Un altro consiste nell'effettuare il calcolo della dimensione nella classe CRTP due volte, una volta come constexpre una volta come not constexpr, e passare entrambi i risultati alla funzione di creazione dell'oggetto derivato: constexprviene passato come argomento modello e non- constexprcome argomento normale. La funzione di creazione è specializzata per matrici statiche e dinamiche. La versione statica ignora i non constexprparametri e viceversa.

Jarod42 Aug 22 2020 at 17:58

A quanto ho capito, potresti aggiungere quel metodo di fabbrica all'interno Derived:

Se some_number_of_rows, some_number_of_colspuò essere constexpr (per soddisfare il più vincolato Derived) in entrambi i casi, potresti fare qualcosa del tipo:

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 {}; }
};

Insieme a

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

altrimenti devi spostare quel calcolo anche nelle funzioni derivate:

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 {}; }
};

Insieme a

auto result = self.CreateEmptyTransposed();