【问题标题】:Which data structure to use for huge but constant dictionary in C++哪种数据结构用于 C++ 中巨大但不变的字典
【发布时间】:2011-09-17 10:08:08
【问题描述】:

我必须使用带有整数(或枚举)键和字符串值的巨大字典。但这是完全不变的。无法在运行时更改。有没有办法(使用模板等)在编译时检索字典数据,而不是使用现有的字典结构?

【问题讨论】:

  • 数据从何而来?例如,模板不能从文件中读取。所以答案很可能是,你不能在编译时这样做。
  • @Oli:你总是可以#include 文件。
  • 他们不能,但也许你可以在编译之前将配置文件转换为 C++ 文件。自动代码生成可能会解决这个问题。
  • 键的密度有多大(它们更像 {0,1,2,4,5,7} 还是 {2001, 7012, 15234})?
  • @Rudi 我提到了枚举。所以,它们就像 {0,1,2,4,5,7}

标签: c++ data-structures dictionary constants


【解决方案1】:

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
}

在 Clang 和 LLVM 中,代码生成阶段用于从更令人愉快的定义文件生成 .inc。

它工作得很好......但请注意,对枚举的任何修改都意味着完全重新编译。您可能希望采用“代码集”方法,其中枚举在内部使用但从不泄漏到外部,并向客户端(unsigned)提供稳定值(枚举的值),以便旧客户端可以链接到无需重新编译的新库:它们将被限制使用旧代码集,如果它是稳定的就没有问题。

【讨论】:

    【解决方案2】:

    当然,您可以简单地使用 sed 将字典转换为由模板参数索引的字符串常量,头文件如下:

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

    还有一个包含多行格式的源文件:

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

    另一方面,您真的想从维护的角度来做这件事吗?它需要为每个更改的字典条目和臃肿的可执行文件大小重新编译。

    【讨论】:

    • Bloated:嗯,条目需要在某个地方,至少在 ROM 中意味着它不会在程序的各种实例中重复(如果是 DLL)。 重新编译:这可能是个问题,除非你有合适的接口。
    【解决方案3】:

    自动代码生成怎么样?获取配置文件或数据库或任何来源,并从中生成 C++ 标头代码。它可能看起来像这样:

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

    您可以使用简单的 bash 脚本或 ruby​​/python(或 C++,如果您是受虐狂)进行转换,这取决于您的配置文件的复杂性。

    然后编写一些make规则,在配置文件发生变化时自动创建头文件。

    【讨论】:

    • 对不起,我当时正在做饭,恐怕我忘记了评论:x 首先,这没有解决枚举 字符串映射一个 iota。第二请不要将宏用于文字/常量,有更好的选择(外部常量、静态常量等...)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-24
    • 1970-01-01
    • 2013-02-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多