Reputation: 131
Lets say I have a CRTP template class for matrices
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() {}
// ...
};
How can I check for the Derived class type in MatrixBase::some_function(const Derived &other)
to use this base function in both derived classes?, preventing the need for redefinition/override/code duplicates in these classes separately. In this case it is basically only the declaration of the result
matrix that requires me to check for the Derived class type, as the declaration is different depending on if its a fixed-size or dynamic matrix. Other solutions than type-checking are also welcome.
NOTE: I cannot use standard functionality due to the nature of my application.
EDIT: The some_number_of_rows
and some_number_of_cols
in the example function are in general not constexpr, as they are dependent on the function and size of the object matrix. For instance for a transpose
function, the result would have to have dimension <Derived.n_cols, Derived.n_rows
, and in the case of a column-wise dot product, <1, Derived.n_cols>
.
Upvotes: 3
Views: 214
Reputation: 120229
This is a challenging problem. Basically, some_number_of_rows
and some_number_of_cols
must be constexpr
in case of StaticMatrix
, and cannot be constexpr
in case of DynamicMatrix
.
One solution is to delegate new matrix creation to the derived class. It will do the size computation as constexpr
or not constexpr
, whichever works for it.
Another one is to make the size computation in the CRTP class twice, once as constexpr
and once as not constexpr
, and pass both results to the derived object creation function: constexpr
is passed as a template argument, and non-constexpr
as a regular argument. The creation function is specialized for both static and dynamic matrices. The static version ignores the non-constexpr
parameters, and vice versa.
Upvotes: 1
Reputation: 218323
As I understand, you might add those factory method inside Derived
:
If some_number_of_rows
, some_number_of_cols
can be constexpr (to satisfy the more constrained Derived
) in both case, you might do something like:
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 {}; }
};
With
auto result = Derived::Create<some_number_of_rows, some_number_of_cols>();
else you have to move that computation into Derived functions too:
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 {}; }
};
With
auto result = self.CreateEmptyTransposed();
Upvotes: 0