D.T
D.T

Reputation: 13

How do I prevent a instantiation of a template class?

I'm working on a templated matrix class and currently working on the template determinant function. It's a recursive function that finds the determinate of each sub matrix all the way down to the base case and adds/subtracts each of these sub determinate's together. Here's the function:

//Determinant - Only square matrices have a determinant
template <typename T, std::size_t size>
T Determinant(Matrix<T, size, size> &mat)
{
    ASSERT(size >= 2, "Wtf? 1x1 matrix?")

    T determinant = {};

    //Base case - Smallest size of matrix we can calculate the determinant is 2x2
    if (size == 2)
    {
        return ((mat.m_data[0][0] * mat.m_data[1][1]) - (mat.m_data[0][1] * mat.m_data[1][0]));
    }
    else //otherwise, we need to grab the sub matrix within the current matrix and get the determinate of those. 
    {
        Matrix<T, size - 1, size -1 > subMatrix;

        //Note: We're filling in the new sub matrix column order
        for (int topRow_ColumnIndex = 0; topRow_ColumnIndex < size; ++topRow_ColumnIndex)
        {
            int newSubCol = 0;
            for (int subCol = 0; subCol < size; ++subCol)
            {
                int newSubRow = 0;

                if (subCol == topRow_ColumnIndex)
                {
                    continue;
                }

                //Sub matrices will start one row below the top row.
                for (int subRow = 1; subRow < size; ++subRow)
                {
                    subMatrix[newSubCol][newSubRow] = mat[subCol][subRow];
                    ++newSubRow;
                }
                ++newSubCol;
            }
            determinant = determinant + (T)pow(-1, topRow_ColumnIndex) * mat.m_data[topRow_ColumnIndex][0] *Determinant(subMatrix);
        }
    }
    return determinant;
}

The issue I'm having is with the template portion of this. Specifically this part of the code:

Matrix<T, size - 1, size - 1 > subMatrix;

What this is intended to do is to create a matrix with dimensions that fit the sub matrix (which is 1 less than the current).

What's happening is that this specific template is being instantiated:

Matrix<float, 0, 0> 

which is a no go since the underlying data in the matrix is an array, and we can't have zero length arrays.

1) Is there any way to prevent this specific template from being instantiated?

2) Possibly a stupid question but I'm calling this function with a Matrix3x3 passed in. Why does the compiler instantiate every template with a dimension of 3 all the way down to 0? (A low level explanation would be great if possible)

Upvotes: 1

Views: 93

Answers (2)

Jarod42
Jarod42

Reputation: 217135

If you have access to C++17, you might use if constexpr instead of regular if for to not instantiate the "discarded" branch:

if constexpr (size == 2)

Upvotes: 0

iBug
iBug

Reputation: 37227

You can specialize Determinant<T, 1> so it doesn't create Matrix<T, 0, 0>.

template <typename T>
T Determinant<T, 1> (Matrix<T, 1, 1> &mat) {
    // Implementation here
    // Avoid Matrix<T, 0, 0>
}

You can also specialize Determinant<T, 2> so you can drop the if else inside, since checking for template variables is better done at compile time.

template <typename T, std::size_t size>
T Determinant<T, size> (Matrix<T, size, size> &mat) {
    // original "else" part here
}

template <typename T>
T Determinant<T, 2> (Matrix<T, 2, 2> &mat) {
    return ((mat.m_data[0][0] * mat.m_data[1][1]) - (mat.m_data[0][1] * mat.m_data[1][0]));
}

Upvotes: 2

Related Questions