Szablon przeładowanego operatora

0

Witam! Robię kalkulator macierzowy w C++.
Mam też zaimplementowaną klasę complex.
Teraz chciałbym przeciążyć operator dodawania w taki sposób, żeby:
Jeśli dodamy macierze short int i int zwracało int, int i double - double, a jak dodamy np double i complex, żeby zwracało matrix <complex>.
Zasadnicze pytanie - czy da się to w ogóle zrobić, czy trzeba poprzeciążać operatory dla wszystkich przypadków?
Wymyśliłem coś takiego, że można by wykorzystać sizeof();
bo:
sizeof(short int) = 2;
sizeof(int) = 4;
sizeof(double) = 8;
sizeof(complex) = 16;
I teraz po prostu funkcja by zwracała większy typ.

template <class T>
class matrix
{
	...
	template <typename X>
	matrix < tu nie wiem jak :( > operator+ (const matrix <X> & a)
	{
		if(sizeof(T)>=sizeof(X)) {zwracaj matrix <T>} else {zwracaj matrix <X>}
	}

};
2

Moze sie wydawac dosc magiczne, ale dziala tak, jak tego oczekujesz (C++11, sprawdzone na GCC 4.7.1)

#include <iostream>
#include <vector>
#include <typeinfo>
#include <cassert>

struct complex
{
    double re;
    double im;
    complex(double re = 0.0, double im = 0.0) : re(re), im(im) {}
};

complex operator+(complex lhs, const complex& rhs)
{
    lhs.re += rhs.re;
    lhs.im += rhs.im;
    return lhs;
}

template<typename T>
class matrix
{
public:
    //...
private:
    std::vector<std::vector<T>> data;
    
    template<typename T1, typename T2>
    friend auto operator+(const matrix<T1>& lhs, const matrix<T2>& rhs) -> matrix<decltype(lhs.data[0][0] + rhs.data[0][0])>;
};

template<typename T1, typename T2>
auto operator+(const matrix<T1>& lhs, const matrix<T2>& rhs) -> matrix<decltype(lhs.data[0][0] + rhs.data[0][0])>
{
    typedef decltype(lhs.data[0][0] + rhs.data[0][0]) TOut;
    matrix<TOut> res;
    return res;
}

int main(int argc, char** argv)
{
    matrix<int> a;
    matrix<double> b;
    matrix<complex> c;
    
    assert(typeid(a) == typeid(matrix<int>));
    assert(typeid(a+b) == typeid(matrix<double>));
    assert(typeid(b+a) == typeid(matrix<double>));
    assert(typeid(a+c) == typeid(matrix<complex>));
    assert(typeid(c+a) == typeid(matrix<complex>));
}

Kodu jest duzo, bo podalem dzialajacy przyklad. Sama istota przeladowania tkwi tutaj:

template<typename T1, typename T2>
auto operator+(const matrix<T1>& lhs, const matrix<T2>& rhs) -> matrix<decltype(lhs.data[0][0] + rhs.data[0][0])>
{
    typedef decltype(lhs.data[0][0] + rhs.data[0][0]) TOut;
    matrix<TOut> res;
    // wlasciwe dodawanie
    return res;
}

Funkcja zwraca matrix<T>, gdzie T jest dedukowany na podstawie wyniku dodawania pol w dwoch macierzach i dziala tu normalna promocja typow. Np. jesli T1 == int i T2 == double, to wynikiem dodawania jest double.

Edit Na Ideone nie dziala zaprzyjaznienie, przez co sypie bledami. Rozwiazaniem jest wyrzucenie deklaracji przyjazni z matrix i upublicznienie pola data. W praktyce z pewnoscia bedzie tam publiczny operator()(int row, int col) (albo inny akcesor), z ktorego mozna skorzystac w funkcji bez potrzeby zaprzyjazniania jej.

0

Rozwiązanie prawie dokładnie tego problemu ktoś już napisał:

http://www.cs.indiana.edu/cgi-bin/techreports/TRNNN.cgi?trnum=TR542

Pkt. 1.8.2 Type promotion example

0

O to bardziej przystępne dzięki

1 użytkowników online, w tym zalogowanych: 0, gości: 1