2010-07-29 10 views
6

ich eine Templat C++ Klasse, die eine Reihe von Methoden aussetzt, zBHinzufügen von Methoden zur Vorlage Spezialisierung

template<int X, int Y> 
class MyBuffer { 
public: 
    MyBuffer<X,Y> method1(); 
}; 

Nun, ich zusätzliche Methoden dieser Klasse verfügbar machen möchten, wenn X == Y. ich dies getan habe durch Unterklassen MyBuffer,

template<int X> 
class MyRegularBuffer : public MyBuffer<X,X> { 
public: 
    MyRegularBuffer method2(); 
}; 

Nun ist das Problem, dass ich in der Lage sein möchte, z

MyRegularBuffer<2> buf = ... 
MyRegularBuffer<2> otherBuf = buf.method1().method2(); 

Aber ich bin mir nicht sicher, wie dies zu erreichen ist. Ich habe versucht, an Kopierkonstruktoren, Konvertierungsoperatoren usw. zu denken, aber meine C++ - Kenntnisse sind leider ein wenig eingerostet.

EDIT: Ich möchte, dass die Schöpfung dieser Objekte hinzufügen relativ billig ist (und auch, es wird nicht viel passieren), was bedeutet, es wäre in Ordnung, so etwas zu tun:

MyRegularBuffer<2> buf = ... 
MyRegularBuffer<2> temp = buf.method1(); // Implicit conversion 
MyRegularBuffer<2> otherBuf = temp.method2(); 

Die Frage ist dann, wie kann ich die Konvertierung so definieren. Der Konvertierungsoperator muss in MyBuffer sein, denke ich, aber ich möchte, dass er nur verfügbar ist, wenn X == Y ist.

+1

völlig unverständlich. Zum Beispiel sprechen Sie über "den Konvertierungsoperator", aber es gibt keinen. Veröffentlichen Sie einen echten Code. –

+0

@Neil, ich denke, der Benutzer hat eine echte Frage nach besten Kräften gestellt. Und ich denke ich verstehe es etwas. –

+0

@Aaron In diesem Fall, bitte teilen Sie Ihr Verständnis. –

Antwort

5

Sie benötigen keine separate Klasse brauchen das besondere Verhalten darzustellen. Teilspezialisierung ermöglicht es Ihnen, einige der MyBuffer < X, Y > Fälle speziell zu behandeln und ihnen zusätzliche Methoden zu geben.

Bewahren Sie die Originalerklärung MyBuffer < X, Y > und hinzufügen:

template<int Y> 
class MyBuffer<Y, Y> { 
public: 
    MyBuffer<Y,Y> method1(); 
    MyBuffer<Y,Y> method2(); 
}; 

MyBuffer<1,2> m12; m12.method2(); // compile fail, as desired, as it doesn't have such a method because 1 != 2 
MyBuffer<2,2> m22; m22.method2(); // compile success 

Edit: meine letzten Zeilen schließlich nicht sehr nützlich waren, wie von Georg in den Kommentaren darauf hingewiesen, also habe ich sie gelöscht.

+1

Der einzige Nachteil ist, dass method1() in MyBuffer neu implementiert werden muss, oder der Compiler wird sich über eine unbekannte Methode beschweren, wenn Sie versuchen, MyBuffer :: method1() aufzurufen. AFAIK, gibt es keine Möglichkeit, MyBuffer :: method1() seine Implementierung zu MyBuffer :: method1() zu delegieren, ohne andere Template-Parameter anzugeben, wobei X! = Y. –

+0

Ableiten von 'MyBuffer' würde nicht funktionieren - es doesn kenne die abgeleitete Klasse nicht und kann daher den entsprechenden Typ nicht aus 'method1()' zurückgeben. –

+0

@Georg, verstehe ich nicht. Können Sie genauer festlegen, welche Leitung ausfallen wird? Ich habe meinen Code kompiliert und es funktioniert. Aber ich muss zugeben, dass ich die letzte Zeile falsch über "Klasse MyRegularBuffer" kopiert habe. Wird jetzt aktualisiert. –

1

Es ist möglich zu tun, was Sie wollen, wenn method1 und method2 einen Verweis auf *this zurückgeben. Andernfalls müssen Sie entweder eine Konvertierung durchführen oder method1 virtuell machen.

+0

Auch wenn method1() das zurückgibt, können Sie method2() immer noch nicht von seinem Rückgabewert aufrufen, weil method2() nicht Teil der Schnittstelle von MyBuffer ist. – wilhelmtell

+0

Können Sie den virtuellen Methodenansatz näher erläutern? Ich bin mir nicht sicher, ob ich das verstanden habe ... Das Problem, vor dem ich stehe, ist der Vertrag, die Implementierung wäre dieselbe (die Objekte sind im Speicher identisch, wenn X == Y, also könnte ich einfach eine Neuinterpretation machen). – Krumelur

+0

wilhelmelt, ja, genau das, was ich meinte. Du warst schneller :) – Krumelur

1

Der Trick ist eine MyRegularBuffer::method1 zu haben, die MyBuffer::method1 nennt, dann einen Weg, um die resultierende MyBuffer<X,X> in eine MyRegularBuffer<X> zu konvertieren:

template<int X> 
class MyRegularBuffer : public MyBuffer<X,X> 
{ 
public: 

    MyRegularBuffer<X>() 
    {} 

    MyRegularBuffer<X>(MyBuffer<X,X>) 
    { 
    // copy fields, or whatever 
    } 

    MyRegularBuffer<X> method2(); 

    MyRegularBuffer<X> method1() 
    { 
    MyRegularBuffer<X> ret(MyBuffer<X,X>::method1()); 
    return(ret); 
    } 
}; 
+0

Danke. Ja, das ist eine gute Idee, aber in meinem Fall fügt es der Lösung von @Aaron McDaid nichts hinzu, da ich method1 erneut implementieren muss (method1 ist eigentlich eine Anzahl von Methoden). – Krumelur

3

würde ich für CRTP hier gehen:

template<int X, int Y, class Derived> 
struct MyBufferBase { 
    // common interface: 
    Derived& method1() { return *static_cast<Derived*>(this); } 
}; 

template<int X, int Y> 
struct MyBuffer : MyBufferBase<X, Y, MyBuffer<X,Y> > { 
    // basic version 
}; 

template<int X> 
struct MyRegularBuffer : MyBufferBase<X, X, MyRegularBuffer<X> > { 
    // extended interface: 
    MyRegularBuffer& method2() { return *this; } 
}; 
+0

+1 Danke, dass Sie mich daran erinnert haben. –

+0

Danke dafür. Das ist absolut eine gute Idee. – Krumelur

+0

Ich hätte als Antwort markiert, wenn ich mehr als eine Antwort hätte geben können, aber im Moment fällt Aaron McDaids Lösung tatsächlich ziemlich gut aus, da meine Methoden ziemlich dünn sind (es ist eine Wrapper-Klasse). – Krumelur

Verwandte Themen