我正在为大学项目编写自己的库,其中包含模板类:Vector和Matrix。除了这些模板类之外,还有用于 vector 和矩阵的相关模板函数。教授明确告诉我们将矩阵定义为一维数组,其中元素按列排序(效率/优化的原因)。 “矩阵”模板类具有3个模板参数:矩阵允许的数据类型,行数,列数。
template <class T, unsigned int M, unsigned int N>
class Matrix
话虽如此,我立即解决了这个问题。我正在编写一个函数,使用列的LaPlace规则(使用第一列)来计算任何维度> 4的矩阵的行列式。我还编写了一个针对二维矩阵的函数(称为D2MatrixDet)和一个针对三维矩阵的函数(称为D3MatrixDet),这些函数已经过测试并可以正常工作:
template <class T>
double D2MatrixDet(const Matrix<T, 2, 2>& _m)
template <class T>
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
我必须编写的模板函数具有两个模板参数:输入矩阵的数据类型,矩阵的维数(由于行列式是针对平方矩阵计算的,因此仅一个维就足够了)。它是一个递归函数;变量“结果”是在每个步骤中将行列式存储在内存中的变量。下面是我编写的代码。template <class T, unsigned int D>
void DNMatrixDet(Matrix<T, D, D> _m, double result) //LaPlace Rule respect to the first column
{
const unsigned int new_D = D - 1;
Matrix<T, new_D, new_D> temp;
if (D > 3)
{
for (unsigned int i = 0; i < _m.row; ++i)
//Indicate the element to multiply
{
for (unsigned int j = _m.row, l = 0; j < _m.row * _m.column && l < pow(new_D, 2); ++j)
//Manage the element to be inserted in temp
{
bool invalid_row = false;
for (unsigned int k = 1; k < _m.row && invalid_row == false; ++k) //Slide over row
{
if (j == (i + k * _m.row))
{
invalid_row = true;
}
}
if (invalid_row == false)
{
temp.components[l] = _m.components[j];
++l;
}
}
DNMatrixDet(temp, result);
result += pow((-1), i) * _m.components[i] * result;
}
}
else if (D == 3)
{
result += D3MatrixDet(_m);
}
}
我主要使用5 x 5矩阵测试该功能。当我尝试编译时,会出现一些错误,所有错误都非常相似,并且与矩阵的大小有关,矩阵的大小每步减小1。这是当初始矩阵大小为5时(LA是库的名称,而Test.cpp是包含主文件的文件):
LA.h: In instantiation of 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 5]':
Test.cpp:437:33: required from here
LA.h:668:34: error: no matching function for call to 'D3MatrixDet(LA::Matrix<double, 5, 5>&)'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
In file included from Test.cpp:1:
LA.h:619:12: note: candidate: 'template<class T> double LA::D3MatrixDet(const LA::Matrix<T, 3, 3>&)'
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
^~~~~~~~~~~
LA.h:619:12: note: template argument deduction/substitution failed:
In file included from Test.cpp:1:
LA.h:668:34: note: template argument '5' does not match '3'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
这是当大小变为4时:LA.h: In instantiation of 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 4]':
LA.h:662:28: required from 'void LA::DNMatrixDet(LA::Matrix<T, M, M>, double) [with T = double;
unsigned int D = 5]'
Test.cpp:437:33: required from here
LA.h:668:34: error: no matching function for call to 'D3MatrixDet(LA::Matrix<double, 4, 4>&)'
In file included from Test.cpp:1:
LA.h:619:12: note: candidate: 'template<class T> double LA::D3MatrixDet(const LA::Matrix<T, 3, 3>&)'
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
^~~~~~~~~~~
LA.h:619:12: note: template argument deduction/substitution failed:
In file included from Test.cpp:1:
LA.h:668:34: note: template argument '4' does not match '3'
result += D3MatrixDet(_m);
~~~~~~~~~~~^~~~
等等。它一直下降直到从4294967295(我发现这是32位“unsigned int”的上限)开始重新开始,一直下降直到达到模板实例的最大数量(= 900)为止。在每次迭代中,即使仅在输入矩阵为3 x 3时才执行该函数,编译器始终会检查该函数以计算3 x 3的行列式。因此,为什么要检查理论上永远不应该进行的检查即将发生?
即使在纸上写的矩阵的帮助下,我也仔细检查了几次编写的数学逻辑,并缓慢地执行了第一步。我相信并希望它是对的。我很确定问题与使用模板和递归函数有关。
对于很长的问题,我深表歉意,我试图以最好的方式进行解释。我希望我已经很好地解释了这个问题。
编辑:
通过在DNMatrixDet函数的开头定义“if constexpr”来解决问题。编译成功。我只需要修复算法,但这超出了本文的范围。下面是进行更改的reprex:
template <class T, unsigned int M, unsigned int N>
class Matrix
{
public:
T components[M * N];
unsigned int row = M;
unsigned int column = N;
Matrix()
{
for (unsigned int i = 0; i < M * N; ++i)
{
components[i] = 1;
}
}
Matrix(T* _c)
{
for (unsigned int i = 0; i < M * N; ++i, ++_c)
{
components[i] = *_c;
}
}
friend std::ostream& operator<<(std::ostream& output, const Matrix& _m)
{
output << _m.row << " x " << _m.column << " matrix:" << std::endl;
for (unsigned int i = 0; i < _m.row; ++i)
{
for (unsigned int j = 0; j < _m.column; ++j)
{
if (j == _m.column -1)
{
output << _m.components[i + j*_m.row];
}
else
{
output << _m.components[i + j*_m.row] << "\t";
}
}
output << std::endl;
}
return output;
}
};
template <class T>
double D3MatrixDet(const Matrix<T, 3, 3>& _m)
{
double result = _m.components[0] * _m.components[4] * _m.components[8] +
_m.components[3] * _m.components[7] * _m.components[2] +
_m.components[6] * _m.components[1] * _m.components[5] -
(_m.components[6] * _m.components[4] * _m.components[2] +
_m.components[3] * _m.components[1] * _m.components[8] +
_m.components[0] * _m.components[7] * _m.components[5]);
return result;
}
template <class T, unsigned int D>
void DNMatrixDet(Matrix<T, D, D> _m, double result)
{
Matrix<T, D - 1, D - 1> temp;
if constexpr (D > 3)
{
for (unsigned int i = 0; i < D; ++i)
{
for (unsigned int j = D, l = 0; j < D * D && l < (D - 1) * (D - 1); ++j)
{
bool invalid_row = false;
for (unsigned int k = 1; k < D && invalid_row == false; ++k)
{
if (j == (i + k * D))
{
invalid_row = true;
}
}
if (invalid_row == false)
{
temp.components[l] = _m.components[j];
++l;
}
}
DNMatrixDet(temp, result);
result += i & 1 ? -1 : 1 * _m.components[i] * result;
}
}
else if (D == 3)
{
result += D3MatrixDet(_m);
}
}
int main()
{
double m_start[25] = {4, 9, 3, 20, 7, 10, 9, 50, 81, 7, 20, 1, 36, 98, 4, 20, 1, 8, 5, 93, 47, 21, 49, 36, 92};
Matrix<double, 5, 5> m = Matrix<double, 5, 5> (m_start);
double m_det = 0;
DNMatrixDet(m, m_det);
std::cout << "m is " << m << std::endl;
std::cout << "Det of m is " << m_det << std::endl;
return 0;
}
最佳答案
当您以类型_m
作为参数Matrix<T, 5, 5>
传递时,结尾的else分支包含代码result += D3MatrixDet(_m);
。编译器仍将尝试对此进行编译,并注意找不到匹配的构造函数。
由于我们在编译时就知道是否采用该分支,因此可以通过使用if constexpr
来指示编译器。由于我们位于模板内,因此如果该分支被丢弃,编译器将不再对其进行检查。
因此,让我们将if (D > 3)
更改为if constexpr (D > 3)
。
关于c++ - 递归模板函数内的无限循环,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64136273/