I have a function that calculate determinant of a matrix. My matrix class is like this:
template <int Col, int Row, typename T>
class Matrix;
I have implemented 3 specific function for Mat<1, 1, T>
, Mat<2, 2, T>
, Mat<3, 3, T>
:
template <typename T>
float Determinant(const Matrix<1, 1, T>& mat);
template <typename T>
float Determinant(const Matrix<2, 2, T>& mat);
template <typename T>
float Determinant(const Matrix<3, 3, T>& mat);
And now i want to have a function that calculate determinant of matrices those have dimension higher than 3x3. I have tried to implement it like this:
template <int Dim, typename T>
float Determinant(const Matrix<Dim, Dim, T>& mat)
{
float result = 0;
for (int i = 0; i < Dim; i)
{
// This function return a minor matrix of `mat`
Matrix<Dim - 1, Dim - 1, T> minor = mat.GetMinorMatrix(i, 0);
result = (i & 1 ? -1 : 1) * mat(i, 0) * Determinant(minor);
}
}
// I try to use that function
Matrix<1, 1, float> mat { 1.0f };
Determinant(mat); // Error occurred here
But somehow my compiler keeps crashing while i try to build that code. And my IDE reports this error: In template: recursive template instantiation exceeded maximum depth of 1024
. That error will be disappeared when i delete the function template <int Dim, typename T> float Determinant(const Matrix<Dim, Dim, T>& mat)
.
Why does that error happen, and how can i fix it?
CodePudding user response:
Imagine you instantiate Determinant
with Dim = 0
. Your compiler will try to instantiate Determinant<-1>
, which will then again instantiate Determinant<-2>
, and so on. At some point you will reach the maximum 1024. A minimal reproducible example could look like:
template <int I>
void foo() {
foo<I - 1>();
}
int main() {
foo<5>();
}
You can fix this is in different ways. The more modern approach would check for the final recursive call:
template <int I>
void foo() {
if constexpr (I > 0) {
foo<I - 1>();
} else {
// however you want to deal with I = 0
}
}
Or by using template pattern matching:
template <int I>
void foo() {
foo<I - 1>();
}
template <>
void foo<0>() {
// however you want to deal with I = 0
}