How to avoid infinite recursion in C ++ class templates

I have a matrix class with a size determined by template parameters.

template <unsigned cRows, unsigned cCols>
class Matrix {
    ...
};

My program uses matrices of several sizes, usually 2x2, 3x3 and 4x4. By setting the size of the matrix with the template parameters, and not the runtime parameters, you can do a lot of inlays and optimization for the compiler.

But now I need a member function that returns a new matrix that contains fewer rows and less column.

Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const { ... }

The idea is that it will return a matrix with the specified row and column. In practice, this will only ever be called with a matrix that has at least three rows and three columns, returning 2x2 on the smallest.

The compiler does not see the lower bound, so it gets stuck in infinite recursion, trying to create patterns with ever-decreasing sizes. I tried to put two hints in the function itself that these smaller sizes cannot happen:

Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const {
    static_assert(cRows > 1 && cCols > 1);
    if (cRows <= 1 || cCols <= 1) throw std::domain_error();
    Matrix<cRows - 1, cCols - 1> r;
    // ... initialize r ...
    return r;
}

Neither for static_assertnor for if-statement seems to convincingly tell the compiler that the 0x0 matrix will never be generated. (Ironically, he complains about a if-state having a constant compile-time condition.)

Does anyone have any suggestions on how to avoid this infinite recursion at compile time?

+3
source share
5 answers

, .

.

template<unsigned cRows>
class Matrix< cRows, 0 >
{
    Matrix<cRows - 1, 0> Reduced() { return Matrix<cRows - 1, 0>(); }
};


template<unsigned cCols>
class Matrix< 0, cCols >
{
    Matrix<0, cCols - 1> Reduced() { return Matrix<0, cCols - 1>(); }
};


template<>
class Matrix< 0, 0 >
{
    Matrix<0, 0> Reduced() { return Matrix<0, 0>(); }
};

, Matrix Reduced (cRows-1, cCols -1). ​​-. - , .

, , , , 1x1, 2x2.

template<>
class Matrix< 1, 1 > {};
+12

cRows cCols, .

+1

, , , , , 0, 0, .

, ++ Templates: The Complete Guide Vandervoorde Josuttis, .

+1

, . . DDJ. :

template<int n>
class META_FACTORIAL
{
public:
  enum{
    RET = n * META_FACTORIAL<n-1>::RET
  };
};

template<>
class META_FACTORIAL<0>
{
public:
  enum{ RET = 1 };
};
0

Instead of specializing the entire class to complete the recursion, another option would be to use a boost::enable_iffunction to make it available only when the matrix size is above 2x2.

0
source

Source: https://habr.com/ru/post/1714726/


All Articles