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

如何用C++宏实现带注册功能的自定义枚举类生成?

实现自定义枚举结构体的C++宏方案

核心问题解析

标准C++预处理器不允许在宏展开内部直接定义新宏——你之前在MY_ENUM_BEGIN里写的#define ENUM_ENTRY会被当作普通文本处理,无法生效。要实现需求,得用分层宏替换+临时宏占位的技巧,把ENUM_ENTRY的定义和结构体生成逻辑绑定。

完整实现代码

#include <map>
#include <string>

// 临时宏:定义枚举项、注册函数
#define MY_ENUM_TEMP_ENTRY(name, val, desc) \
    static constexpr auto name = val; \
    static void register_##name() { \
        _map.insert({val, desc}); \
    }

// 清理临时宏,避免污染全局空间
#define MY_ENUM_CLEANUP() \
    #undef ENUM_ENTRY

// 启动宏:定义结构体框架,重定向ENUM_ENTRY到临时宏
#define MY_ENUM_BEGIN(StructName) \
    struct StructName { \
        static inline std::map<int, std::string> _map; \
        static void register_all() { \
            // 所有条目注册调用会在这里展开 \
        } \
        #define ENUM_ENTRY MY_ENUM_TEMP_ENTRY

// 结束宏:闭合结构体,清理临时宏
#define MY_ENUM_END() \
    }; \
    MY_ENUM_CLEANUP()

// 使用示例
MY_ENUM_BEGIN(fun)
ENUM_ENTRY(item1, 1, "item 1")
ENUM_ENTRY(item2, 2, "item 2")
ENUM_ENTRY(item3, 3, "item 3")
MY_ENUM_END()

// 测试代码
#include <iostream>
int main() {
    fun::register_all();
    for (auto& pair : fun::_map) {
        std::cout << pair.first << ": " << pair.second << std::endl;
    }
    std::cout << "item1的值:" << fun::item1 << std::endl;
    return 0;
}

展开逻辑说明

  1. MY_ENUM_BEGIN(fun) 展开后:

    • 生成struct fun框架,包含静态映射容器_map和空的批量注册函数register_all
    • 通过#define ENUM_ENTRY MY_ENUM_TEMP_ENTRY,把后续的ENUM_ENTRY全部重定向到临时宏
  2. ENUM_ENTRY(item1,1,"item 1") 被替换为:

    static constexpr auto item1 = 1;
    static void register_item1() {
        _map.insert({1, "item 1"});
    }
    
  3. MY_ENUM_END() 展开后:

    • 闭合结构体定义
    • 调用MY_ENUM_CLEANUP()取消ENUM_ENTRY的定义,防止影响其他代码

优化:自动生成批量注册逻辑

上面的示例需要手动在register_all里调用每个register_*函数,我们可以修改宏让注册逻辑自动生成:

// 修改临时宏和启动宏
#define MY_ENUM_TEMP_ENTRY(name, val, desc) \
    static constexpr auto name = val; \
    static void register_##name() { \
        _map.insert({val, desc}); \
    }

#define MY_ENUM_BEGIN(StructName) \
    struct StructName { \
        static inline std::map<int, std::string> _map; \
        static void register_all() { \
            static bool _initialized = false; \
            if (_initialized) return; \
            _initialized = true; \
    #define ENUM_ENTRY(name, val, desc) \
            register_##name(); \
            MY_ENUM_TEMP_ENTRY(name, val, desc)

#define MY_ENUM_END() \
        } \
    }; \
    MY_ENUM_CLEANUP()

修改后,register_all会自动包含所有条目注册函数的调用,无需手动添加。

注意事项

  • 必须严格按MY_ENUM_BEGIN→ENUM_ENTRY→MY_ENUM_END的顺序使用,否则宏展开会出错
  • 临时宏MY_ENUM_TEMP_ENTRY和MY_ENUM_CLEANUP不要在其他场景使用,避免冲突
  • 如果需要支持非int类型的枚举键,直接修改_map的模板参数和MY_ENUM_TEMP_ENTRY的参数即可

内容的提问来源于stack exchange,提问作者Mosklia Voidref

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 16:50:09