2017-12-28 41 views
0

Angenommen, ich habe eine Template-Klasse, zum Beispiel template<int n, int m> class MatrixPerfect Forwarding mit Template-Klassen

Gibt es eine Möglichkeit, einen Matrix-Multiplikation Operator * zu definieren, so dass

  1. die Argumente * entweder lvalues ​​sein können oder R-Wert verweist
  2. * den entsprechenden Rückgabetyp folgert (dh die entsprechenden Template-Parameter) von seinen Argumenten

Was ich im Sinne habe etwas wie

template< int n,int k, int m, template<int,int> class T1, template<int, int> class T2, template<int,int>class T3 > 
T3<n,m> operator*(T1<n,k>&&, T2<k,m>&&)//does not work 

Wenn ich versuche, den obigen Code (mit den Körpern ausgefüllt in der offensichtlichen Weise) zu laufen, bekomme ich einen Fehler:

Cannot convert from Matrix<1,1> to Matrix<1,1>&&

, wenn die Argumente sind lvalues.

+1

"Funktioniert nicht" bedeutet, dass Sie einen Compilerfehler erhalten? Wenn ja, was ist dieser Fehler? – tadman

+1

Tippfehler? Sie beginnen mit ' vu1p3n0x

+0

@tadmad: siehe die Bearbeitung, @ vu1p3n0x: Danke, behoben –

Antwort

2

Ja. Aus meinem eigenen Code:

template 
< 
    int LeftColumnsRightRows, int LeftRows, 
    int RightColumns 
> 
Matrix<RightColumns, LeftRows> operator*(Matrix<LeftColumnsRightRows, LeftRows> const& a, Matrix<RightColumns, LeftColumnsRightRows> const& b) 

Und ich weiß nicht, warum Sie es && s nehmen wollen würden. Wenn Sie zwei andere Typen in Matrizen konvertieren und dann multiplizieren möchten, sollten Sie die Konvertierung außerhalb des Multiplikationsoperators durchführen.

+0

Danke. Ich möchte, dass && s so ist, dass ich zusammengesetzte Ausdrücke wie A * B * C schreiben kann. –

+0

Ich habe Probleme damit, dies zum Laufen zu bringen. Nachdem ich diese Deklaration gemacht habe (und meine Klasse wie in meiner Frage deklariert habe), bekomme ich einen Fehler: "Template-Argument für Nicht-Typ-Template-Parameter muss ein Ausdruck sein" –

+0

Die Funktion gibt eine neue Matrix-Instanz zurück, so dass zusammengesetzte Ausdrücke funktionieren sollten ohne '&&' s. Ich habe die Signatur geändert, damit sie besser zu Ihren Deklarationen passt. – user673679

2

Ich würde einfach zu const Referenzen bleiben, wie von der vorherigen Antwort erläutert. Aber um zu verdeutlichen, warum Ihr Code nicht funktioniert, gilt die perfekte Weiterleitung nur dann, wenn Sie einen rvalue-Verweis auf einen cv-unqualifizierten Template-Parameter verwenden. In juristischer Hinsicht hat es nur T&& sein, wo T ein Funktions-Template-Parameter ist:

template<class T> 
void ForwardMe(T&& t) 
{ 
    DoSomething(std::forward<T>(t)); 
} 

Die Idee ist, dass der Compiler in der Lage sein wird, T als type& abzuleiten, wenn ein L-Wert übergeben (so die Funktionssignatur wird void ForwardMe(type&) wegen der kollabierenden Referenzregeln) oder nur type im Falle von rvalues ​​(Signatur wird void ForwardMe(type&&)).

In Ihrem Beispiel haben Sie so etwas wie:

template<int N, template<int> class T> 
void ForwardMe(T<N>&& t) 
{ 
    // ... 
} 

Dies als Sie erwartet hatte nicht funktioniert, weil der Compiler nicht T ableiten kann ein Hinweis auf etwas zu sein, so dass Sie nicht perfekt machen können Weiterleitung Der Funktionsparameter t stimmt daher nur mit rvalue-Referenzen überein.

Da const-Referenzen an Provisorien binden können, lösen Sie im obigen Beispiel const T<N>&, um Ihre Probleme zu lösen. Aber wenn Sie wirklich beide L-Wert und R-Wert-Eingänge unterstützen wollen (weil Sie bewegen Semantik haben, wo zutreffend), haben Sie zwei Möglichkeiten:

  • schreiben Überlastungen für alle 4 Permutationen: L-Wert * L-Wert, L-Wert * R-Wert, rvalue * lvalue, rvalue * rvalue.
  • Schreiben Sie eine generische Funktionsschablone und verwenden Sie SFINAE, um die Eingabetypen zu begrenzen.

Letzteres wäre so etwas wie:

#include <type_traits> 

template<class L, class R> 
struct MatrixMulResult_helper; 
template<int n, int m, int k, template<int, int> class T> 
struct MatrixMulResult_helper<T<n, m>, T<m, k>> { using type = T<n, k>; }; 

template<class L, class R> 
using MatrixMulResult = typename MatrixMulResult_helper<L, R>::type; 

template<class L, class R> 
MatrixMulResult<std::decay_t<L>, std::decay_t<R>> 
operator*(L&& lhs, R&& rhs) 
{ 
    // ... 
} 

Der Compiler ist jetzt frei L und R als Bezugnahmen abzuleiten. MatrixMulResult<> stellt sicher, dass diese Funktion nur dann definiert ist, wenn (die verfallenen Typen von) L und R jeweils die Form T<n,m> und T<m,k> haben. Es gibt eine T<n,k> zurück.