Home > front end >  C template function recursive
C template function recursive

Time:09-07

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
}
  • Related