【问题标题】:Templated Matrix Class Not Generating Functions Correctly模板化矩阵类未正确生成函数
【发布时间】:2010-08-19 08:55:26
【问题描述】:

基本上,我有一个这样的矩阵类(删除了很​​多运算符重载和其他函数):

template
<
    uint32 TRows,
    uint32 TCols
>
struct Matrix
{
    float values[TRows][TCols];

    inline explicit Matrix()
    {
    }

    inline Matrix<TRows - 1, TCols - 1> minor(const uint32 col, const uint32 row)
    {
        Matrix<TRows - 1, TCols - 1> matrix;
        for(int i = 0; i < TRows; ++i)
            for(int j = 0; j < TCols; ++j)
            {
                if(i == col || j == row) continue;
                matrix.values[i - (i > col)][j - (j > row)] = this->values[i][j];
            }
        return matrix;
    }

    inline float determinant()
    {
        if(TRows != TCols) throw DimensionError("Matrix is not square");

        float det = 0;

        if(TRows <= 0)
            det = 0;
        else if(TRows == 1)
            det = this->values[0][0];
        else if(TRows == 2)
            det = this->values[0][0] * this->values[1][1] - this->values[1][0] * this->values[0][1];
        else
            for(int j = 0; j < TCols; ++j)
                det += (j % 2 ? -1 : 1) * this->values[0][j] * this->minor(0, j).determinant();

        return det;
    }
}

我不明白为什么,对于 det += (j % 2 ? -1 : 1) * this-&gt;values[0][j] * this-&gt;minor(0, j).determinant(); 行,GCC 会尝试生成大量函数:

matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -49u, unsigned int TCols = -49u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -48u, unsigned int TCols = -48u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -47u, unsigned int TCols = -47u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -46u, unsigned int TCols = -46u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -45u, unsigned int TCols = -45u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -44u, unsigned int TCols = -44u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -43u, unsigned int TCols = -43u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -42u, unsigned int TCols = -42u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -41u, unsigned int TCols = -41u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -40u, unsigned int TCols = -40u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -39u, unsigned int TCols = -39u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -38u, unsigned int TCols = -38u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -37u, unsigned int TCols = -37u]'
matrix.cpp:95:   instantiated from `float Matrix<TRows, TCols>::determinant() [with unsigned int TRows = -36u, unsigned int TCols = -36u]'

这可能是我的代码中的一些错误,但我无法终生看到哪里出错了。非常感谢您的帮助!

【问题讨论】:

    标签: c++ templates matrix


    【解决方案1】:

    Matrix::minor(0, j) 返回一个大小为 (N-1, N-1) 的矩阵。 调用其行列式会使过程递归,这意味着您正在为所有 p 整数生成一个次要(和行列式方法),从 N 开始到 ... -infinity ?

    您是否为 N==1 或 N==0 的情况添加了专门化? 你必须确保递归停止!

    尝试添加类似的内容:

    template<>
    struct Matrix<1,1>
    {
      float values[1][1];
    
      float determinant(){ return values[0][0]; }
    };
    

    编辑: 递归必须在编译时停止。在方法中添加 if 语句不会阻止编译器编译所有可能的路径。

    【讨论】:

    • 谢谢!有用!不过,您的代码中只是一个小错字 -- int float 应该只是 float :)
    • @rfw:这是一个动态时间分支,你需要一个静态时间分支。为 0 大小的矩阵添加特化。
    【解决方案2】:

    我同意“Benoît”

    运行时期间,您永远不会在“空”矩阵上调用minor 函数这一事实 - 不会阻止编译器生成该代码。

    为避免这种情况,您应该使用显式模板特化。这样即使在编译时,编译器也不会遇到导致无限模板函数生成的程序路径。

    喜欢这个:

    template <int N>
    float determinantInternal()
    {
        // Standard algoritm for NxN matrix
        float det = 0;
        for(int j = 0; j < TCols; ++j)
            det += (j % 2 ? -1 : 1) * this->values[0][j] * this->minor(0, j).determinant();
    
        return det;
    }
    
    template <>
    float determinantInternal<0>()
    {
        return 0;
    }
    
    float determinantInternal<1>()
    {
        return this->values[0][0];
    }
    
    float determinantInternal<2>()
    {
        return this->values[0][0] * this->values[1][1] - this->values[1][0] * this->values[0][1];
    }
    
    template <>
    float determinant()
    {
        if (TRows != TCols)
            throw DimensionError("Matrix is not square");
        // Alternatively you can use something to prevent this from compiling. 
        // This way you produce the compile-time error if attempted to call
        // determinant on a non-square matrix
        BOOST_STATIC_ASSERT(TRows == TCols);
    
        return determinantInternal<TRows>();
    }
    

    这种专业化的另一个优点是您可以在编译时处理不同的矩阵类型(空、非正方形、1x1、NxN)。因此,您会获得更快的代码。

    另外,您可以防止在非方阵上调用 determinant。在这种情况下,您将在尝试执行此操作时收到编译器/链接器错误,而不是在运行时出现异常。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-21
      • 2010-10-02
      • 2013-11-22
      • 2016-09-26
      • 1970-01-01
      相关资源
      最近更新 更多