2011-09-17 57 views
5

我必須使用帶有整數(或枚舉)鍵和字符串值的巨大字典。但這是完全不變的。無法在運行時更改。有沒有一種方法(使用模板等)在編譯時檢索字典數據,而不是使用現有的字典結構?哪個數據結構在C++中用於龐大而恆定的字典

+3

數據來自哪裏?例如,模板無法從文件讀取。所以最有可能的答案是,在編譯時你不能這樣做。 –

+1

@Oli:你總是可以包含#include文件。 –

+0

他們只能在編譯之前將配置文件轉換爲C++文件。自動代碼生成可能會解決問題。 –

回答

5

Clang和LLVM通過使用代碼生成和預處理器欺騙的組合生成包含它們的對象的表,解決了您的問題。

根據您自己的設置,您可以跳過任一步驟。例如:現在

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

,您可以生成您的枚舉:

// 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 
} 

在鐺和LLVM,一個代碼生成階段被用於從更愉快的定義文件。公司。

它工作得很好......但請注意,枚舉的任何修改都意味着完全重新編譯。您可能希望採用「代碼集」方法,其中枚舉在內部使用但絕不會泄露到外部,並向客戶端提供穩定的值(枚舉值)(unsigned),以便舊客戶端可以鏈接到新的沒有重新編譯的庫:它們將被限制使用舊的代碼集,如果它是穩定的,這是沒有問題的。

3

當然,你可以簡單地使用SED改造字典字符串常量通過模板參數索引,與像一個頭文件:

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

,並與形式的多行源文件:

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

另一方面,你是否真的想從維護的角度來做到這一點?它需要重新編譯每個更改的字典條目和臃腫的可執行文件大小。

+0

* Bloated *:好的,條目需要在某處,至少在ROM中它意味着它不會在程序的各種實例中重複(如果DLL )。 *重新編譯*:這可能是一個問題,除非你有一個適當的界面。 –

0

自動代碼生成如何?採取配置文件或數據庫或任何來源,並從中生成C++頭代碼。它可能是這個樣子:

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

你可以做轉換用一個簡單的bash腳本或者用拼音/ Python(或C++,如果你是受虐狂),這取決於您的配置文件的複雜性。

然後編寫一些make規則在配置文件更改時自動創建頭文件。

+0

我有一個大風扇,無時無刻都在低估着我。 –

+0

Oups對不起,我當時正在做飯,恐怕我忘了評論:x首先,這並沒有解決enum <->字符串映射一個iota。第二*請*不要使用宏作爲文字/常量,有更好的選擇(外部常量,靜態常量等)。 –