2010-07-29 15 views
6

Ho una classe su modelli C++ che espone una serie di metodi, ad esempiometodi Aggiunta di modello di specializzazione

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

Ora, voglio esporre i metodi aggiuntivi per questa classe se X == Y. ho fatto questo sottoclassi MyBuffer,

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

Ora, il problema è che voglio essere in grado di fare ad es.

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

Ma non sono sicuro di come farlo. Ho provato a pensare a costruttori di copie, operatori di conversione, ecc., Ma le mie competenze in C++ sono sfortunatamente un po 'arrugginite.

EDIT: Vorrei aggiungere che la creazione di questi oggetti è relativamente a buon mercato (e anche, non accadrà molto), il che significa che sarebbe stato OK per fare qualcosa di simile:

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

Il la domanda è quindi, come posso definire la conversione in questo modo. L'operatore di conversione deve essere in MyBuffer, penso, ma voglio che sia disponibile solo se X == Y.

+1

del tutto incomprensibile. Ad esempio, parli di "l'operatore di conversione", ma non ce n'è. Pubblica un po 'di codice reale. –

+0

@Neil, penso che l'utente abbia posto una vera domanda al meglio delle proprie capacità. E penso di capirlo un po '. –

+0

@Aaron In tal caso, condividi la tua comprensione. –

risposta

5

non hai bisogno di una classe separata per rappresentare il comportamento speciale. La specializzazione parziale ti consente di trattare alcuni dei casi di MyBuffer < X, Y > in modo speciale e di fornire loro metodi aggiuntivi.

Mantenete il vostro originale della dichiarazione di mybuffer < X, Y > e aggiungere questo:

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: miei versi finali non erano molto utile, dopo tutto, come sottolineato da Georg nei commenti, quindi li ho cancellati.

+1

L'unico svantaggio è che method1() deve essere implementato nuovamente in MyBuffer , altrimenti il ​​compilatore si lamenterà di un metodo sconosciuto quando si tenta di chiamare MyBuffer :: method1(). AFAIK, non c'è modo di avere MyBuffer :: method1() delegare la sua implementazione a MyBuffer :: method1() senza specificare parametri di template diversi dove X! = Y. –

+0

Derivante da 'MyBuffer' non funzionerebbe - non funziona Conosciamo la classe derivata e quindi non possiamo restituire il tipo appropriato da 'method1()'. –

+0

@ Georg, non capisco. Puoi essere più specifico su quale linea fallirà? Ho compilato il mio codice e funziona. Ma devo ammettere che ho copiato erroneamente l'ultima riga su "class MyRegularBuffer". Si aggiornerà ora. –

1

È possibile eseguire ciò che si desidera se method1 e method2 restituiscono un riferimento a *this. In caso contrario, sarà necessario eseguire una conversione o rendere virtuale method1.

+0

Anche se method1() restituisce ciò, non è ancora possibile chiamare method2() dal valore restituito, poiché method2() non fa parte dell'interfaccia di MyBuffer . – wilhelmtell

+0

Puoi approfondire l'approccio al metodo virtuale? Non sono sicuro di averlo capito ... Il problema che sto affrontando è il contratto, l'implementazione sarebbe la stessa (l'oggetto è identico in memoria se X == Y, quindi potrei semplicemente fare una reinterpretazione). – Krumelur

+0

wilhelmtell, sì, esattamente quello che intendevo. Sei stato più veloce :) – Krumelur

1

Il trucco è quello di avere un MyRegularBuffer::method1 che chiama MyBuffer::method1, quindi un modo per convertire la risultante MyBuffer<X,X> in un MyRegularBuffer<X>:

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

Grazie. Sì, questa è una buona idea, ma nel mio caso non aggiunge nulla alla soluzione di @Aaron McDaid, in quanto devo ancora implementare method1 (metodo1 è in realtà un numero di metodi). – Krumelur

3

mi piacerebbe andare per CRTP qui:

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 Grazie per avermelo ricordato. –

+0

Grazie per quello. Questa è assolutamente una buona idea. – Krumelur

+0

Avrei contrassegnato come risposta se avessi potuto dare il marchio a più di una risposta, ma in questo momento la soluzione di Aaron McDaid cade in realtà abbastanza bene, poiché i miei metodi sono piuttosto sottili (è una classe wrapper). – Krumelur

Problemi correlati