Kamil Zaripov
Kamil Zaripov

Reputation: 990

Template compare operator

I have a following template class:

template<int size, typename Type>
class Matrix {
    public:
        Matrix();
        ...
        Type operator ()(int row, int column) {...}
    private:
        std::array<Type, size*size> _array;
}

And I want to overload equal to comparison operator to compare Matrix objects:

template <int size, typename LeftType, typename RightType>
bool operator ==(const Matrix<size, LeftType> & left, const Matrix<size, RightType> & right) {
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            ...
        }
    }
}

The problem is that comparison of integer types and real types is quite different:

real case:

template <int size, typename LeftType, typename RightType>
bool operator ==(const Matrix<size, LeftType> & left, const Matrix<size, RightType> & right) {
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            if (qFuzzyIsNull(left(i, j)) || qFuzzyIsNull(right(i, j))) {
                if (!qFuzzyCompare(left(i, j) + 1, right(i, j) + 1)) {
                    return false;
                }
            } else {
                if (!qFuzzyCompare(left(i, j), right(i, j))) {
                    return false;
                }
            }
        }
    }
    return true;
}

(I'm using Qt's qFuzzyCompare and qFuzzyIsNull)

integer case:

template <int size, typename LeftType, typename RightType>
bool operator ==(const Matrix<size, LeftType> & left, const Matrix<size, RightType> & right) {
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            if (left(i, j) != right(i, j)) {
                return false;
            }
        }
    }
    return true;
}

How to enable integer case if both LeftType and RightType integer and enable real case if at least one LeftType or RightType is real?

Upvotes: 0

Views: 997

Answers (1)

Aziuth
Aziuth

Reputation: 3902

How about this:

template <int size, typename LeftType, typename RightType>
bool operator ==(const Matrix<size, LeftType> & left, const    Matrix<size,    RightType> & right) {
    for (int i = 0; i < size; ++i) {
        for (int j = 0; j < size; ++j) {
            if (not is_equal(left(i,j), right(i,j)) {
                return false;
            }
        }
    }
    return true;
}

and then you either define several overloaded variants of is_equal or make is_equal a template and define it's specializations, like

template<class T> 
bool is_equal(const T a, const T b);

template<>
bool is_equal<int>(const int a, const int b){
    return a == b;
}

template<>
bool is_equal<real>(const real a, const real b){
    ...
}  

(or as a template over two types if that can happen)

You could, of course, specialize the operator itself, but that means that you have to write the same code all over again without any chance that you will reuse it. Meanwhile, is_equal could become some common tool in your program.

(note: is_equal is a somewhat basic name, so it should be in a namespace, obviously)

Upvotes: 1

Related Questions