0

Problem

I am getting a C2087 'm': missing subscript compile error and two C4200 nonstandard extension used: zero-sized array in struct/union warnings when I try to calculate the determinant of a Matrix recursively.

I have a Matrix class that stores the data of the matrix in a 2D array m where the size is given from template parameters int rows and int columns.

Note: I have looked into another post about missing subscript c++ but it does not exactly answer my question since my 2D array has it's size defined by the template parameters and is not left empty.

Code

Here is my MRE that produces the error, built in Visual Studio 2019:

Matrix.h

#include <iostream>
#include <assert.h>

template <typename T, int rows, int columns>
struct Matrix
{
private:
    const int size = rows * columns;
    union
    {
        T m[rows][columns];
        T a[rows * columns];
    };

public:
    Matrix()
    {
        for (int i = 0; i < size; ++i)
            a[i] = T(0);
    }

    Matrix(T* a_)
    {
        for (int i = 0; i < size; ++i)
            a[i] = a_[i];
    }

    T& operator[](int index)
    {
        return a[index];
    }

    Matrix<T, rows - 1, columns - 1> LaplaceMatrix(int row, int column)
    {
        Matrix<T, rows - 1, columns - 1> res;

        int index = 0;
        for (int i = 0; i < rows; ++i)
        {
            if (i == row)
                continue;

            for (int j = 0; j < columns; ++j)
            {
                if (j == column)
                    continue;

                res[index] = m[i][j];
                ++index;
            }
        }

        return res;
    }

    T Determinant()
    {
        assert(rows == columns);

        if (rows == 2)
            return m[0][0] * m[1][1] - m[0][1] * m[1][0];

        T determinant = T(0);
        for (int i = 0; i < size; ++i)
        {
            if (m[0][i] != 0)
            {
                if (i % 2 == 0)
                {
                    Matrix<T, rows - 1, columns - 1> laplace = LaplaceMatrix(0, i);
                    T det = laplace.Determinant();
                    determinant += (m[0][i] * det);
                }
                else
                {
                    Matrix<T, rows - 1, columns - 1> laplace = LaplaceMatrix(0, i);
                    T det = laplace.Determinant();
                    determinant -= (m[0][i] * det);
                }
            }
        }

        return determinant;
    }
};

Main.cpp

int main()
{
    int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    Matrix<int, 3, 3> m(a);
    
    Matrix<int, 2, 2> laplace = m.LaplaceMatrix(0, 0);
    std::cout << laplace.Determinant() << std::endl;

    return 0;
}
m.a.g
  • 21
  • 3
  • 1
    What happens when you call `LaplaceMatrix` on a 1x1 matrix? – Igor Tandetnik May 22 '23 at 03:17
  • 1
    Also, be aware that this approach of computing determinant is extremely inefficient. [Better algorithms exist](https://en.wikipedia.org/wiki/Determinant#Calculation) – Igor Tandetnik May 22 '23 at 03:20
  • 2
    "store the data of this matrix in a union" This combines all the advantages of undefined behaviour with all the advantages of extra code complexity. – n. m. could be an AI May 22 '23 at 03:54
  • Please post a [mre] and the exact text of the error you mentioned. – Bob__ May 22 '23 at 08:09
  • Did you perhaps forget to specialize the base case (2x2)? (Also, you should make sizes less than 2 invalid, as well as non-square matrices.) – molbdnilo May 22 '23 at 08:10
  • @IgorTandetnik when I call `LaplaceMatrix` on a 1x1 matrix I get the same error. Also thank you for the reference link, I will look into it for improvements. – m.a.g May 22 '23 at 19:52
  • @JaMiT I have rewritten the question after reviewing the details in the link you referenced, along with an MRE that produces the error. – m.a.g May 22 '23 at 20:42
  • @Bob__ I have rewritten the question and included an MRE as requested. – m.a.g May 22 '23 at 20:43
  • @molbdnilo I have an if statement for the 2x2 case and an assert to ensure that the matrix is a square matrix in my `Determinant` function – m.a.g May 22 '23 at 20:43
  • Thanks. Have you already studied [constexpr if statements](https://en.cppreference.com/w/cpp/language/if#Constexpr_if)? It would [solve](https://godbolt.org/z/KcKssK633) your immediate problem, but I'd consider a complete refactor of the code, getting rid of the union. – Bob__ May 22 '23 at 21:21
  • @m.a.g At eruntime is too late. – molbdnilo May 22 '23 at 21:53
  • @Bob__ I see. I am not too familiar with constexpr if statements. I'll take your advice and go for a refactor – m.a.g May 22 '23 at 22:24
  • @molbdnilo I'm not familiar with how to make that check at compile time – m.a.g May 22 '23 at 22:24
  • Are you still getting "missing subscript" with the current example? When I tried compiling it, I only got errors corresponding roughly to your "zero-sized array in struct/union" warning. Was there more to that warning? Such as a place in the code where it occurs? A mention of which template is being instantiated? I think clang gives a clearer error message than what you're getting: `error: 'm' declared as an array with a negative size` `note: in instantiation of member class 'Matrix::(anonymous union at prog.cc:9:5)'`. I would highlight the `-1` in `Matrix`... – JaMiT May 27 '23 at 14:39
  • Related, but dealing with function templates: [invalid instantiation of template by compiler giving error](https://stackoverflow.com/q/67816795) – JaMiT May 27 '23 at 14:40
  • Does this answer your question: [Compile time recursion and conditionals](https://stackoverflow.com/q/8759872) – JaMiT May 27 '23 at 14:47

0 Answers0