Perse95
Perse95

Reputation: 121

If statement called when comparison of template parameter is false

I'm writing a templated matrix class using C++14. This class has three template parameters: the type of data stored (dtype), the number of rows (N) and the number of columns (M).

The class signature is

template<class dtype, size_t N, size_t M>
class Matrix

I've written a determinant member function that calls specific cases when a template parameter has a certain value. For example, when the number of rows is 1 it returns a copy of the matrix itself. Alternatively, when the number of rows is 2 or 3 it returns a 1x1 matrix of the same datatype with the determinant. Finally, when the number of rows is more than 3 it uses a recursive method to calculate the determinant based on the cofactor expansion of the determinant.

I am doing this as an exercise to better learn C++14 so I'd be very grateful for some help.

The code snippet causing issues is this part right here:

Matrix<dtype, 1, 1> det() const {
    if (N != M || N >= 12) {
        return Matrix<dtype, 1, 1>();
    } else if (N == 1) {
        return this->copy();
    } else if (N == 2) {
        return Matrix<dtype, 1, 1>(this->get(0, 0) * this->get(1, 1) - this->get(0, 1) * this->get(1, 0));
    } else if (N == 3) {
        return Matrix<dtype, 1, 1>(
                this->get(0, 0) * (this->get(1, 1) * this->get(2, 2) - this->get(1, 2) * this->get(2, 1)) -
                this->get(0, 1) * (this->get(1, 0) * this->get(2, 2) - this->get(1, 2) * this->get(2, 0)) +
                this->get(0, 2) * (this->get(1, 0) * this->get(2, 1) - this->get(1, 1) * this->get(2, 0)));
    } else if (N < 12) {
        Matrix<dtype, 1, 1> determinant;
        Matrix<dtype, N - 1, N - 1> sub_matrix;
        for (size_t i = 0; i < N; ++i) {
            sub_matrix = this->drop_cross(i, i);
            Matrix<dtype, 1, 1> sub_det(sub_matrix.det());
            if (i % 2 == 0) determinant = determinant + (this->get(0, i) * sub_det);
            else if (i % 2 == 1) determinant = determinant - (this->get(0, i) * sub_det);
        }
        return determinant;
    }
}

This function is called by this code:

#include "lin_alg_classes.h"

int main() {
    Matrix<double, 3, 3> test3(1.0, true);

    std::cout << std::endl;
    std::cout << test3.det();

    return 0;
}

And gives the following output:

In file included from C:\Users\ekin4\CLionProjects\mt_grav\main.cpp:5:0:
C:\Users\ekin4\CLionProjects\mt_grav\lin_alg_classes.h: In instantiation of 'Matrix<dtype, 1ull, 1ull> Matrix<dtype, N, M>::det() const [with dtype = double; long long unsigned int N = 3ull; long long unsigned int M = 3ull]':
C:\Users\ekin4\CLionProjects\mt_grav\main.cpp:29:28:   required from here
C:\Users\ekin4\CLionProjects\mt_grav\lin_alg_classes.h:132:31: error: could not convert 'Matrix<dtype, N, M>::copy<double, 3ull, 3ull>()' from 'Matrix<double, 3ull, 3ull>' to 'Matrix<double, 1ull, 1ull>'
             return this->copy();

What I don't understand is why it is calling the N = 1 case when it should be calling the N < 12 case. I have checked braces, parentheses and semicolons, and they are all correct, but for the life of me I don't understand what is happening.

Upvotes: 0

Views: 90

Answers (1)

max66
max66

Reputation: 66190

Pre c++17 (if constexpr) you can use SFINAE and enable/disable different versions of det() according the values of N and M.

Something like (sorry: not tested)

template <std::size_t A = N, std::size_t B = M>
std::enable_if_t<(A != B) || (A > 11U), Matrix<dtype, 1, 1>> det() const
 { return Matrix<dtype, 1, 1>(); }

template <std::size_t A = N, std::size_t B = M>
std::enable_if_t<(A == B) && (A == 1U), Matrix<dtype, 1, 1>> det() const
 { return this->copy(); }

// other cases

Upvotes: 1

Related Questions