2016-04-10 7 views
5

Diciamo che ho una classe C++:Evitare C++ istanze esplosive di classi template che accettano i parametri int

template<int N> 
class Text { 
    public: 
     Text() { } 
     char _buf[N]; 
}; 

Si incapsula semplicemente una stringa C.

Ora, diciamo che scrivo un metodo che richiederà un altro oggetto Text, con una lunghezza M e ne copia il contenuto in questo oggetto.

template<int N> 
class Text { 
    public: 
     Text() { } 
     char _buf[N]; 

     template<int M> void copy(const Text<M> &t) { 
      strncpy(_buf, t.cstr(), N - 1); 
      _buf[N - 1] = '\0'; 
     }    
}; 

È questo che va causare un'esplosione di codice oggetto duplicato in cui l'unica differenza sono le costanti N e M utilizzati, soprattutto se uso questo metodo copy con oggetti che hanno un sacco di differenti N e M?

Poiché il metodo stesso non dipende da M affatto, c'è un altro modo di affrontare questo in modo tale da evitare questa esplosione di codice oggetto duplicato?

+6

Quello che per lo più accadere è che tutte le chiamate di copia sarà inline in modo che non funzioni reali saranno emessi a tutti. Sembra un'ottimizzazione prematura che dovrebbe essere semplicemente ignorata. – Jack

+0

In realtà, no. Il mio codice oggetto ha raddoppiato le dimensioni dall'uso di solo un paio di valori di N e M. Sto cercando di mantenere le dimensioni del codice oggetto in basso. – Ana

+0

Lo stai compilando con i flag di ottimizzazione? – Jack

risposta

3

L'approccio più evidente è scomporre i bit comuni in una classe di base, ad es .:

class TextBase { 
public: 
    char* text; 
    int n; 
    TextBase(char* text, int N): text(text), n(N) {} 
    void copy(const TextBase &t) { 
     strncpy(this->text, t.text, n - 1); 
     this->text[n - 1] = '\0'; 
    } 
}; 
template<int N> 
class Text: public TextBase { 
public: 
    Text(): TextBase(_buf, N) { } 
    char _buf[N]; 
}; 

Si scambia formato oggetto di un potenziale miglioramento della dimensione del codice. Deve essere ovvio perché è stata la prima cosa che mi è venuta in mente mentre mi svegliavo ancora. Invece di viaggiare in termini di una base assumendo il parametro in una forma di cancellazione del tipo si evita la necessità di spazio aggiuntivo, ad es. (Questo approccio mi è venuta in mente quando essere un po 'più lontano dal risveglio):

template<int N> 
class Text { 
public: 
    Text() { } 
    char _buf[N]; 
    operator char const*() const { return this->_buf; } 
    void copy(char const* source) { 
     strncpy(this->_buf, source, N - 1); 
     this->_buf[N - 1] = '\0'; 
    } 
}; 
+0

'TextBase (char *, int)' è abbastanza pericoloso. Basta lasciare la gestione della memoria all'utente. Potrei usare semplicemente il vecchio 'char *' altrettanto bene. –

+0

@ n.m .: basta rendere il 'costrutto' TextBase' protetto'. Se vuoi assicurarti che 'TextBase' sia realmente usato da' Text 'potresti rendere il costruttore' private' e 'template class Text' a' friend'. Tutto ciò è al di là del punto della domanda posta, però. –

+0

Non sei sicuro che stai ottenendo una classe utilizzabile in questo modo. Come si restituiscono queste cose dalle funzioni, ecc. –

0

In generale, penso che C++ 11 introdotto extern template per fare questo:

Una dichiarazione esplicita di istanza (un modello esterno) impedisce le istanze implicite : il codice che altrimenti causerebbe una istanziazione implicita deve utilizzare la definizione di istanza esplicita fornita da qualche altra parte nel programma (in genere, in un altro file: questo può essere utilizzato per ridurre i tempi di compilazione)

Tuttavia, per il tuo caso d'uso, dovresti istanziare esplicitamente Text :: copy per tutte le combinazioni di N e M, quindi non sembra fattibile e la risposta di Dietmar sarebbe un'alternativa migliore.

1

Come già accennato, la soluzione potrebbe essere una classe base con un metodo virtuale puro per ottenere il buffer. Non sono richiesti attributi aggiuntivi e _buf potrebbe essere privato.

Qualcosa di simile a questo:

class TextBase { 
public: 
    virtual const char* cstr() const =0; 
}; 

template<int N> 
class Text: public TextBase { 
public: 
    Text() { } 
    void copy(TextBase &t) { 
     strncpy(_buf, t.cstr(), N - 1); 
    _buf[N - 1] = '\0'; } 

protected: 
    virtual const char* cstr() const { 
    return _buf; 
    }; 
private: 
    char _buf[N]; 
// ... 
} 
Problemi correlati