7 Stimmen

C++ implizite Instanziierung von Vorlagen

Ich habe derzeit eine Klassenhierarchie wie

MatrixBase -> DenseMatrix
           -> (other types of matrices)
           -> MatrixView -> TransposeView
                         -> DiagonalView
                         -> (other specialized views of matrices)

MatrixBase ist eine abstrakte Klasse, die Implementierer dazu zwingt, operator()(int,int) und ähnliche Dinge zu definieren; sie repräsentiert 2-dimensionale Arrays von Zahlen. MatrixView steht für eine (möglicherweise veränderbare) Art und Weise, eine Matrix zu betrachten, z. B. durch Transponieren oder durch Aufnahme einer Untermatrix. Der Punkt von MatrixView ist es, etwas sagen zu können wie

Scale(Diagonal(A), 2.0)

wobei Diagonal gibt eine DiagonalView Objekt, das eine Art leichtgewichtiger Adapter ist.

Nun die Frage(n). Ich werde eine sehr einfache Matrixoperation als Beispiel verwenden. Ich möchte eine Funktion definieren wie

template <class T>
void Scale(MatrixBase<T> &A, const T &scale_factor);

die genau das tut, was der Name nahelegt. Ich möchte in der Lage sein, entweder eine echte Nicht-Ansichtsmatrix oder eine Instanz einer Unterklasse von MatrixView . Der oben beschriebene Prototyp funktioniert nicht für Anweisungen wie

Scale(Diagonal(A), 2.0);

weil die DiagonalView Objekt zurückgegeben von Diagonal ist ein temporäres, und Scale nimmt eine nicht-konstante Referenz, die keine temporäre akzeptieren kann. Gibt es eine Möglichkeit, dies zu erreichen? Ich habe versucht, SFINAE zu verwenden, aber ich verstehe es nicht so gut, und ich bin nicht sicher, ob das Problem damit gelöst werden kann. Für mich ist es wichtig, dass diese Template-Funktionen aufgerufen werden können, ohne eine explizite Template-Argumentliste anzugeben (ich möchte eine implizite Instanziierung). Im Idealfall könnte die obige Anweisung wie geschrieben funktionieren.


Edit: (Folgefrage)

Wie sbi unten über rvalue-Referenzen und Temporaries geantwortet hat, gibt es eine Möglichkeit, zwei Versionen von Scale zu definieren, eine, die eine nicht-konstante rvalue-Referenz für Nicht-Ansichten nimmt, und eine, die eine pass-by-value-Ansicht nimmt? Das Problem ist, zwischen diesen beiden zur Kompilierzeit so zu unterscheiden, dass die implizite Instanziierung funktioniert.


更新情報

Ich habe die Klassenhierarchie geändert in

ReadableMatrix
WritableMatrix : public ReadableMatrix
WritableMatrixView
DenseMatrix : public WritableMatrix
DiagonalView : public WritableMatrixView

Der Grund WritableMatrixView ist verschieden von WritableMatrix ist, dass die Ansicht per Const-Referenz weitergegeben werden muss, während die Matrizen selbst per Non-Const-Referenz weitergegeben werden müssen, so dass die Accessor-Member-Funktionen unterschiedliche Const-Eigenschaften haben. Jetzt können Funktionen wie Scale definiert werden als

template <class T>
void Scale(const WritableMatrixView<T> &A, const T &scale_factor);
template <class T>
void Scale(WritableMatrix<T> &A, const T &scale_factor){
    Scale(WritableMatrixViewAdapter<T>(A), scale_factor);
}

Beachten Sie, dass es zwei Versionen gibt, eine für eine Const-Ansicht und eine Non-Const-Version für aktuelle Matrizen. Das bedeutet für Funktionen wie Mult(A, B, C) Ich brauche 8 Überlastungen, aber zumindest funktioniert es. Was allerdings nicht funktioniert, ist die Verwendung dieser Funktionen innerhalb anderer Funktionen. Sie sehen, jede View -ähnliche Klasse enthält ein Mitglied View von dem, was es betrachtet; zum Beispiel in dem Ausdruck Diagonal(SubMatrix(A)) は、その Diagonal Funktion gibt ein Objekt des Typs DiagonalView<SubMatrixView<T> > , die den vollständig abgeleiteten Typ von A . Nehmen wir nun an, dass innerhalb Scale Ich rufe eine andere Funktion auf, die entweder eine Basisansicht oder eine Matrixreferenz benötigt. Das würde fehlschlagen, weil die Konstruktion der benötigten View erfordern den abgeleiteten Typ des Arguments von Scale; Informationen, die es nicht hat. Ich arbeite noch daran, eine Lösung für dieses Problem zu finden.


更新情報

Ich habe verwendet, was ist effektiv eine hausgemachte Version von Boost's enable_if, um zwischen zwei verschiedenen Versionen einer Funktion wie wählen Scale . Es läuft darauf hinaus, alle meine Matrix- und View-Klassen mit zusätzlichen typedef-Tags zu versehen, die angeben, ob sie lesbar oder schreibbar sind und ob es sich um View oder Non-View handelt. Am Ende brauche ich immer noch 2^N Überladungen, aber N ist jetzt nur noch die Anzahl der Nicht-Konst-Argumente. Das Endergebnis finden Sie in der aquí (es ist unwahrscheinlich, dass es noch einmal ernsthaft überarbeitet wird).

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X