我有一个矩阵类,其大小由模板参数决定。
template <unsigned cRows, unsigned cCols>
class Matrix {
...
};
我的程序使用几种尺寸的矩阵,通常为2x2,3x3和4x4。通过使用模板参数而不是运行时参数设置矩阵大小,编译器可以进行大量的内联和优化。
但是现在我需要一个成员函数来返回一个新的矩阵,该矩阵的行数减少一个,列数减少一个。
Matrix<cRows - 1, cCols - 1> Reduced(unsigned row, unsigned col) const { ... }
这个想法是它将返回一个删除了指定行和列的矩阵。在实践中,只会使用至少包含三行和三列的矩阵调用此方法,并在最小的位置返回2x2。
编译器没有看到下限,因此它在无限递归中陷入困境,试图以不断减小的大小实例化模板。我尝试在函数本身中放入两条线索,这些较小的尺寸不会出现:
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;
}
static_assert
和if
- 语句似乎都不足以让编译器永远不会生成0x0矩阵。 (具有讽刺意味的是,它确实抱怨if
- 语句具有恒定的编译时条件。)
有没有人对如何避免这种编译时无限递归有任何建议?
答案 0 :(得分:12)
您需要为没有行或没有列的Matrix提供专门化。
E.g。
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)实例化Matrix模板。这种递归必须在某处停止。如果你只处理方形矩阵,那么你可以减少专业化。
此外,如果您永远不会使用1x1矩阵,那么您可以使用完全为空的类来停止递归,这是2x2矩阵的reduce结果。
template<>
class Matrix< 1, 1 > {};
答案 1 :(得分:1)
您可以为不包含该方法的小值cRows或cCol指定模板特化。
答案 2 :(得分:1)
您似乎对编译时间和运行时行为感到困惑,我对您的代码感到有点困惑,但我认为您想要的是值0,0的模板的特化,它终止了递归。
如果您还没有,我建议您阅读 Vandervoorde&amp ;; C++ Templates: The Complete Guide Josuttis,详细介绍了这类事情。
答案 3 :(得分:0)
您需要明确指定希望递归结束的情况的行为。有关详细信息,请参阅this DDJ article。以下是文章中的一个简单示例:
template<int n>
class META_FACTORIAL
{
public:
enum{
RET = n * META_FACTORIAL<n-1>::RET
};
};
template<>
class META_FACTORIAL<0>
{
public:
enum{ RET = 1 };
};
答案 4 :(得分:0)
不是专门化整个类来终止递归,另一个选择可能是在函数上使用boost::enable_if
,使其仅在矩阵大小超过2x2时可用。