2016-04-21 11 views
0

In meinem C++ Code habe ich eine Matrix-Klasse, und einige Operatoren geschrieben, um sie zu multiplizieren. Meine Klasse ist Templates, was bedeutet, dass ich int, float, double ... Matrizen haben kann.C++ Matrix Multiplikation Typ Erkennung

Mein Betreiber Überlastung des Klassikers I

erraten
template <typename T, typename U> 
    Matrix<T>& operator*(const Matrix<T>& a, const Matrix<U>& b) 
    { 
    assert(a.rows() == b.cols() && "You have to multiply a MxN matrix with a NxP one to get a MxP matrix\n"); 
    Matrix<T> *c = new Matrix<T>(a.rows(), b.cols()); 
    for (int ci=0 ; ci<c->rows() ; ++ci) 
    { 
     for (int cj=0 ; cj<c->cols() ; ++cj) 
     { 
     c->at(ci,cj)=0; 
     for (int k=0 ; k<a.cols() ; ++k) 
     { 
      c->at(ci,cj) += (T)(a.at(ci,k)*b.at(k,cj)); 
     } 
     } 
    } 
    return *c; 
    } 

In diesem Code kehre ich eine Matrix des gleichen Typs als der erste Parameter d Matrix<int> * Matrix<float> = Matrix<int>. Meine Frage ist, wie kann ich den am meisten präzisierten Typ unter den beiden erkennen, die ich gebe, um nicht zu viel Präzision zu verlieren, d. H. Matrix<int> * Matrix<float> = Matrix<float>? Ist es klug, es zu tun?

+0

können Sie Konvertierungen liefern (zB. Matrix 'zu' Matrix ') und erlauben nur den gleichen Typ für die anderen Operationen – user463035818

+1

Sind Sie sicher, das Objekt auf ** Heap ** ist was du was? –

+0

Ich möchte eine Menge Referenz verwenden, um Speicherkopien zu vermeiden. Gibt es einen anderen Weg, es zu tun? – baptiste

Antwort

9

Was Sie wollen, ist nur der Typ, der passiert, wenn Sie eine T durch eine U multiplizieren.

template <class T, class U> 
using product_type = decltype(std::declval<T>() * std::declval<U>()); 

Sie können nur, dass als zusätzliche notleidenden Template-Parameter verwenden: Das kann gegeben sein durch

template <typename T, typename U, typename R = product_type<T, U>> 
Matrix<R> operator*(const Matrix<T>& a, const Matrix<U>& b) { 
    ... 
} 

In C++ 03 Sie das Gleiche erreichen kann durch einen riesigen tun Serie von Überlastungen mit vielen kleinen Helfer Typen wie so (dies ist, wie Boost-tut es):

template <int I> struct arith; 
template <int I, typename T> struct arith_helper { 
    typedef T type; 
    typedef char (&result_type)[I]; 
}; 

template <> struct arith<1> : arith_helper<1, bool> { }; 
template <> struct arith<2> : arith_helper<2, bool> { }; 
template <> struct arith<3> : arith_helper<3, signed char> { }; 
template <> struct arith<4> : arith_helper<4, short> { }; 
// ... lots more 

Wir können dann schreiben:

template <class T, class U> 
class common_type { 
private: 
    static arith<1>::result_type select(arith<1>::type); 
    static arith<2>::result_type select(arith<2>::type); 
    static arith<3>::result_type select(arith<3>::type); 
    // ... 

    static bool cond(); 
public: 
    typedef typename arith<sizeof(select(cond() ? T() : U()))>::type type; 
}; 

Vorausgesetzt, dass Sie die ganze Zahl aller Arten schreiben, dann können Sie typename common_type<T, U>::type verwenden, wo ich vorher product_type verwendet.

Wenn dies keine Demonstration von wie cool C++ 11 ist, weiß ich nicht, was ist.


Hinweis, operator*sollte eine Referenz nicht zurück. Was du machst, wird Speicher verlieren.

+0

Ok ich werde es versuchen. Aber ich verstehe nicht den Unterschied zwischen einem Operator und einer Funktion, die eine Referenz zurückgibt. Ist es eine schlechte Programmierpraxis, Variablen innerhalb einer Funktion zu erstellen und einen Verweis darauf zurück zu geben? – baptiste

+0

Entschuldigung, wenn mir etwas offensichtlich fehlt, aber könnten wir nicht einfach 'auto funcName (blahBlah) -> decltype (T * U)' hier verwenden? –

+0

Übrigens, es gibt kein C++ 11-Tag zu dieser Frage. declltype/auto darf für das OP nicht existieren. Eine Antwort mit Typenmerkmalen könnte angebracht sein. – davidbak