Both branches get generated. If statements are code, not template metacode.
First, write a square matrix class (well you can avoid this, but it makes things easier). (A square matrix being a class templated on one integer size parameter, plus t. It inherits a generic n x n matrix, and forwards constructors onto it. Note that as POD, you can do layout based binary casting safely!). Write a function that takes a generic matrix, and either returns a square matrix or throws.
Write a row removal function that takes a square matrix, and returns a square matrix one smaller.
Then write a template determinate function that takes a square matrix.
Specialize the 1x1 matrix version to simply return the value in the matrix.
Then your non-specialized determinate function reads like your else clause. There is no need to check for rows==1, as that is handled by the specialization.
You can do this without creating the square matrix class, but it can make things easier. :)
...
Actually...
template<int size, typename T>struct determinateHelper { T operator()( Matrix<size, size, T> const& src ) const { // the non-size=1 case }};template<typename T>struct determinateHelper<1, T> { T operator()( Matrix<1, 1, T> const& src ) const { // the size=1 case }};template<int size, typename T>T determinate( Matrix<size,size,T> const& src ) { return determinateHelper<size, T>()(src);}
Now you do compile-time checking on the Matrix passed in. If you pass in a Matrix that isn't square, you fail to compile. :) (This can cause issues down the road).
You can allow for non-square matrix options via:
template< typename Matrix, typename T>T determinate( Matrix const& src ) { throw you_suck(); return T();}
which is an override that will match less than the square matrix, I think (or maybe it won't work, hmm).