You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++静态设置结构设计:如何兼顾多类型、命名访问与编译期特性?

我尝试编写一个相对简单的Settings列表结构,但经过三次失败的设计迭代后,我确定自己缺少一个关键词来准确定位当前问题。

理想需求

  • 每个设置拥有唯一Key,便于反(序列化)
  • 列表中的每个设置是类成员或带有命名访问函数,支持IDE自动补全
  • 每个设置可以是不同类型(String、uint8_t、uint16_t等)
  • 每个设置拥有const char*类型的名称
  • 列表大小在编译期已知,支持随机访问迭代器,可使用数组下标访问

方案一

#define MAKE_UNION(struct_name, struct_def)                     \
  struct __dummy_for_size__##struct_name struct_def;            \
                                                               \
  struct struct_name                                            \
  {                                                            \
    union                                                      \
    {                                                          \
      struct struct_def;                                       \
      uint8_t as_list[sizeof(__dummy_for_size__##struct_name)]; \
    };                                                         \
  };

MAKE_UNION(InputSettings, {
  uint8_t source;
  uint8_t channel;
  bool active;
}) input_settings;

优点

  • 输入input_settings.s时,IDE可自动补全为input_settings.source
  • 可通过input_settings.as_list[?]轻松实现数组下标访问

缺点

  • 代码写法别扭,使用union可能处于未定义行为范畴,此前我甚至还用到了void*强制转换...
  • 仅支持单字节类型,否则as_list的下标访问会失效
  • 无唯一Key,反(序列化)难以实现向前/向后兼容
  • 设置没有C风格字符串名称

方案二

为简洁起见,省略大部分实现代码

struct ISetting{
    const std::string unique_key;
    /*...*/
}; 
class SettingList
{
    std::vector<std::unique_ptr<ISetting>> list;
};

class ValueSetting : public ISetting {/*...*/};
class TextValueSetting : public ISetting{/*...*/};



SettingList input_settings;
input_settings.list.push_back(TextValueSetting{"SOURCE", {"A", "B"}, 0});
input_settings.list.push_back(ValueSetting{"CHANNEL", 0, 15, 0});
input_settings.list.push_back(ValueSetting{"ACTIVE", 0, 1, 1});

auto get_source_setting = [&]{
    return input_settings.list[0];
};

优点

  • 唯一Key便于反(序列化)
  • 设置带有名称

缺点

  • 实现过于复杂
  • 可能存在不必要的运行时多态。此外,由于实际开发中未使用RTTI,我必须通过枚举嵌入类型信息到接口中才能进行向下转换
  • 使用vector但列表大小实际是已知的
  • 设置无命名访问器,需手动编写并维护(如get_source_setting lambda表达式)

方案三

struct Value
{
    uint16_t val;
};
struct TextValue
{
    uint16_t val;
    std::span<std::string_view> values_names;
}; 

std::array<std::pair<std::string, std::variant<Value, TextValue>>, 3> input_settings
{{
    {"SOURCE",  TextValue{ /*... */ }},
    {"CHANNEL", Value{ /*... */ }},
    {"ACTIVE",  Value{ /*... */ }},
    //...
    //...
}};

优点

  • 拥有唯一Key
  • 支持随机访问
  • 可封装为类以实现便捷的get_by_key(std::string)方法

缺点

  • 无命名访问器
  • 无随机访问迭代器
  • 因std::variant的内存布局存在内存浪费(轻微问题)

即使是get_by_key(std::string)也会带来运行时性能开销。或许可以实现编译期的get<key_t>()?

核心问题

如何将不同类型混合到容器中,同时让每个元素自动拥有专属的命名getter/setter?所有元素在编译期已知,希望避免运行时开销。


内容的提问来源于stack exchange,提问作者Nebular Noise

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.25 17:24:29