Well, I can't say that I actually got deep enough into template specializations to resolve the issues grumpy was talking about. But I at least figured out a way to get around the problem--namely by creating friend template functions that create cofactors for square arrays of the given type (T), and then recursively arrive at determinants for these.

So, my array_determinant definition looks like this:

Code:

template<typename T>
T array_determinant(T** arr, const int size)
{
if (size > 1)
{
T det = 0;
T*** cofactor_array = new T**[size];
for (int i = 0; i < size; ++i)
{
cofactor_array[i] = array_cofactor(arr, 0, i, size);
}
// Laplace expansion on first row
for (int i = 0; i < size; ++i)
{
det += arr[0][i] * array_determinant(cofactor_array[i], size - 1);
}
for (int i = 0; i < size; ++i)
{
for (int j = 0; j < size - 1; ++j)
{
delete [] cofactor_array[i][j];
}
delete [] cofactor_array[i];
}
delete [] cofactor_array;
return det;
}
else
return **arr;
}

The big difference here is that size is an INPUT (hence already taken care of when the function compiles) rather than a template parameter.

I hope it's not a horrible ugliness in this code that I still have "if (size > 1)", which (such is my impression anyway) grumpy didn't seem to want to see.

I do think it's pretty ugly having to do all of these deletes. But if we're creating cofactors willy-nilly I don't see much of a way around using dynamic memory allocation, and if you do that, you've got to free up the memory again somewhere, right?

Once you do that, then you get a trivial definition for Matrix determinants:

Code:

template<typename T, int n>
T Matrix<T, n>::determinant() const
{
return array_determinant(content, n);
}

So, no doubt not the greatest code, but at least a way of doing it that seems to work...