2010-09-01 14 views
7

Ho un sacco di codice come questo:parametri di modello, #define e la duplicazione del codice

#define WITH_FEATURE_X 

struct A { 
#ifdef WITH_FEATURE_X 
    // ... declare some variables Y 
#endif 
    void f(); 
}; 

void A::f() { 
    // ... do something 
#ifdef WITH_FEATURE_X 
    // ... do something and use Y 
#else 
    // ... do something else 
#endif 
    // ... do something 
} 

e mi piacerebbe sostituire i #defines con parametri di modello:

template < int WITH_FEATURE_X > // can be 0 or 1 
struct A; 

ma io non voglio duplicare quasi l'intero codice di A :: f() per A < 0> :: f() e A < 1> :: f() solo per le poche righe che dipendono dal parametro. Inoltre, non voglio chiamare funzioni al posto dei precedenti #ifdefs. Qual è la soluzione comune?

risposta

1

Credo che quello che vuoi sia equivalente al comando "statico se" che esiste nel linguaggio D. Temo che una caratteristica del genere non esista in C++.

Si noti che se parti del codice variano a seconda della funzione richiesta, queste parti non appartengono alla funzione principale perché non fanno parte dell'algoritmo. Quindi l'opzione di delegare tali funzioni nelle funzioni sembra buona.

EDIT
Se le sue dichiarazioni #ifdef sono usati per fare la stessa attività secondaria in modo diverso, quindi definendo parziali è la cosa giusta da fare. Renderà il tuo codice più leggibile, non meno.

Se vengono utilizzati per azioni completamente diverse, beh, il codice è già ingombro. Fai qualcosa al riguardo.

Per quanto riguarda il problema di prestazioni che temete possa apparire, fidatevi del vostro compilatore.

EDIT2
Ho dimenticato di dire la risposta alla prima parte del codice: utilizzare il seguente trucco per aggiungere o rimuovere membri a seconda delle "feature".

namespace helper 
{ 
    template<int feature> 
    struct A; 

    template<> 
    struct A<0> { // add member variables for case 0 }; 

    template<> 
    struct A<1> { // add member variables for case 1 }; 
} 

template<int feature> 
class A : private helper::A<feature> 
{ 
    // ... functions here 
}; 
+0

Sì, qualcosa di simile a "statico se" sembra essere necessario. Forse questo è possibile in questo caso con i modelli di boost (come enable_if)? Ho paura che le funzioni ingombrino il codice molto, ci sarebbero chiamate nidificate e il codice diventerebbe piuttosto artificiale, illeggibile e forse meno ottimizzato per la velocità – Thomas

+0

Questa è una bella idea con helper :: A! Proverò a ricodificare alcuni #ifdefs con funzioni e il trucco più tardi e vedere se mi piace il res ult. – Thomas

0

La soluzione comune, è solo per usare #ifdef che ho paura. :-)

0

Non capisco il punto della duplicazione di codice comune. Se stai usando il parametro template stai solo sostituendo il tuo #ifdef con if (WITH_FEATURE_X). Stai parlando di codice gonfiato dal compilatore. Poiché si sta tentando di sostituire #ifdef, presumo che si utilizzi A < 0> o A < 1> in qualsiasi momento. Quindi non vedo un codice gonfiarsi nemmeno dal compilatore.

2

Se si vuole evitare di duplicare la logica della funzione di f è possibile utilizzare il template method pattern (no, non quel tipo di template.

template <bool enabled> 
class helper { 
protected: 
    void foo() { /* do nothing */ } 
}; 

template <> 
class helper<true> { 
protected: 
    Y y; 
    void foo() { /* do something with y */ } 
}; 

struct A : private helper<WITH_FEATURE_X> { 
    void f() { 
     // common stuff 

     foo(); // optimized away when WITH_FEATURE_X is false 

     // more common stuff 
    } 
}; 
+0

Questo sembra essere lo stesso suggerimento di Benoît, ma è bello conoscere il nome del modello e vedere come viene applicato alle funzioni. Grazie. – Thomas

Problemi correlati