2011-09-17 12 views
5

Devo usare un enorme dizionario con chiavi integer (o enum) e valori di stringa. Ma questo è totalmente costante. Non c'è modo di cambiare in runtime. Esiste un modo (utilizzando modelli, ecc.) Per recuperare i dati del dizionario in fase di compilazione invece di utilizzare la struttura del dizionario esistente?Quale struttura dati utilizzare per un dizionario enorme ma costante in C++

+3

Da dove provengono i dati? I modelli non possono leggere da un file, per esempio. Quindi la risposta è, molto probabilmente, che non puoi farlo al momento della compilazione. –

+1

@Oli: puoi sempre # includere i file. –

+0

Non possono, ma forse è possibile trasformare il file di configurazione in un file C++ prima della compilazione. la generazione automatica del codice potrebbe risolvere il problema. –

risposta

5

Clang e LLVM hanno risolto il problema generando tabelle contenenti i loro oggetti, utilizzando una combinazione di generazione del codice e trucchi del preprocessore.

È possibile saltare entrambi i passaggi, in base alla propria configurazione. Per esempio:

// records.inc 
EXPAND_RECORD(Foo, "Foo", 4); 
EXPAND_RECORD(Bar, "Bar", 18); 
EXPAND_RECORD(Bar2, "Bar", 19); 

Ora, è possibile generare il vostro enum:

// records.h 
enum Record { 

#define EXPAND_RECORD(Name, String, Value) Name, 
#include "records.inc" 
#undef EXPAND_RECORD 

}; 

char const* getRecordName(Record r); 
int getRecordValue(Record r); 

// records.cpp 

char const* getRecordName(Record r) { 
    switch(r) { 
#define EXPAND_RECORD(Name, String, Value) case Name: return String; 
#include "records.inc" 
#undef EXPAND_RECORD 
    } 

    abort(); // unreachable, or you can return a "null" value 
} 

int getRecordValue(Record r) { 
    switch(r) { 
#define EXPAND_RECORD(Name, String, Value) case Name: return Value; 
#include "records.inc" 
#undef EXPAND_RECORD 
    } 

    abort(); // unreachable, or you can return a "null" value 
} 

In Clang e LLVM, una fase di generazione di codice viene utilizzato per generare il .inc dai file di definizione più piacevole.

Funziona molto bene ... ma sii consapevole che qualsiasi modifica dell'enumerazione implica la piena ricompilazione. Si potrebbe desiderare di andare a un approccio "codeset", in cui l'enum viene usato internamente ma mai fuoriuscito, e i valori stabili (quelli dell'enum) vengono forniti al client (unsigned), in modo che i vecchi client possano collegarsi al nuovo librerie senza ricompilazione: saranno limitate ad usare il vecchio set di codici, che non è un problema se è stabile.

3

Sicuramente si può semplicemente utilizzare sed per trasformare il dizionario in una stringa costante indicizzato dal parametro del modello, con un file di intestazione come:

template <int Index> struct Dictionary { static const char *entry; }; 

e un file sorgente con molte linee della forma:

template <> const char *Dictionary<5>::entry = "Entry for five"; 

D'altra parte, vuoi davvero farlo dal punto di vista della manutenzione? Implica la ricompilazione per ogni voce del dizionario modificata e dimensioni esecuzioni gonfiate.

+0

* Bloated *: beh, la voce deve essere da qualche parte, almeno averla in ROM significa che non è duplicata tra varie istanze del programma (se DLL). * Ricompilazione *: potrebbe essere un problema, a meno che non si disponga di un'interfaccia corretta. –

0

Informazioni sulla generazione automatica del codice? Prendi il file di configurazione o il database o qualunque sia l'origine e generi codice di intestazione C++ da quello. Potrebbe essere simile a questa:

#define MYCONST_1 "#00ff00" 
#define MYCONST_10 "My other configuration string" 

Si può fare la conversione con un semplice script bash o con Ruby/Python (o C++ se siete masochisti), dipende dalla complessità del file di configurazione.

Quindi scrivere alcune regole di creazione per creare automaticamente i file di intestazione quando il file di configurazione cambia.

+0

Ho un grande fan che mi fa scendere di testa tutto il tempo senza mai commentare .. –

+0

Oups mi dispiace per quello, stavo cucinando in quel momento e temo di aver dimenticato il commento: x In primo luogo, questo non affronta il enum <-> mappatura stringa uno iota. Secondo * per favore * non usare macro per letterali/costanti, ci sono alternative migliori (costante esterna, costante statica, ecc ...). –

Problemi correlati