Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

'if' with templates in C++ [duplicate]

Tags:

c++

templates

I need to do something like this:

template <typename Matrix_xx>
bool ProcessMatrix<Matrix_xx>::function1(Matrix_xx a) {
    int x, y;

    // ... some code here ... //

    if (Matrix_xx == Matrix_1D) {
        a->readFromFile(x);
    } else if (Matrix_xx == Matrix_2D) {
        a->readFromFile(x, y);
    } // ...

}

i.e., to call different functions depends on the template argument. The code above wouldn't compile because there are only Matrix_1D::readFromFile(int x) and Matrix_2D::readFromFile(int x, int y). I don't want to split function1 into two different functions only because there would be a lot of doubled code. Is there another way?

like image 439
Dimath Avatar asked Dec 06 '25 04:12

Dimath


2 Answers

Wrap the type-specific code in either overloaded function or explicitly specialized template:

void doReadFromFile(Matrix_1D &a, int x, int y)
{
    a->readFromFile(x);
}

void doReadFromFile(Matrix_2D &a, int x, int y)
{
    a->readFromFile(x, y);
}

template <typename Matrix_xx>
bool ProcessMatrix<Matrix_xx>::function1(Matrix_xx a) {
    int x, y;

    // ... some code here ... //

    doReadFromFile(a, x, y);
}

If Matrix_xx is Matrix_1D, overloading will select the first overload, if it is Matrix_2D, overloading will select the second overload and if it's anything else, it won't compile. But if somebody provides new type of matrix, they can make it compile by defining the doReadFromFile for it.

This is generally useful trick and reason why standard library uses "traits"—they can be defined for class somebody gives you and they can be defined for non-class types. The "traits" can be either in the form of explicitly specialized templates or free functions, usually looked up with argument-dependent lookup (placed in the namespace of their argument, not the template).

For completeness, the explicit specialization would look like:

template <typename Matrix_xx>
struct doReadFromFile {};

template <>
struct<Matrix_1D> struct doReadFromFile {
    void operator()(Matrix_1D &a, int x, int y) {
        a->readFromFile(x);
    }
}

template <>
struct<Matrix_1D> struct doReadFromFile {
    void operator()(Matrix_1D &a, int x, int y) {
        a->readFromFile(x, y);
    }
}
like image 99
Jan Hudec Avatar answered Dec 08 '25 17:12

Jan Hudec


Couldn't you make the argument to readFromFile a reference to a vector and let the Matrix_xx instance decide how many indices to fill in? That would eliminate the need for a conditional check.

like image 22
otto Avatar answered Dec 08 '25 18:12

otto