C++:如何实现枚举类型的范围遍历并保留枚举值访问特性?
解决多枚举类型的范围遍历问题
首先,保持你原有的枚举定义不变,这样getThingData(Control_0::THING1)这类直接访问的特性完全保留:
namespace regs { enum class Control_0 { THING1, THING2, THING3 }; enum class Control_1 { THING_A, THING_B }; }
接下来针对多枚举的遍历需求,提供两种可行方案:
方案1:类型安全的变体存储(推荐)
利用std::variant统一存储不同枚举类型,既支持范围for循环,又能严格区分枚举类型:
步骤1:定义统一的变体类型和合并的范围
#include <variant> #include <array> namespace regs { // 定义能容纳所有目标枚举的变体类型 using RegVariant = std::variant<Control_0, Control_1>; // 手动列出所有枚举值并合并到统一范围里 constexpr std::array<RegVariant, 5> regs_range = { Control_0::THING1, Control_0::THING2, Control_0::THING3, Control_1::THING_A, Control_1::THING_B }; }
步骤2:遍历并处理不同枚举类型
遍历的时候用std::visit分发到对应的处理逻辑,需要为每个枚举类型实现getThingData的重载:
#include <iostream> // 为每个枚举实现对应的getThingData重载 void getThingData(regs::Control_0 c) { std::cout << "Control_0 value: " << static_cast<int>(c) << "\n"; } void getThingData(regs::Control_1 c) { std::cout << "Control_1 value: " << static_cast<int>(c) << "\n"; } // 范围for循环遍历 int main() { for (const auto& reg : regs::regs_range) { std::visit([](auto val) { getThingData(val); }, reg); } return 0; }
方案2:底层类型统一存储(适合不需要严格区分类型的场景)
如果所有枚举的底层类型一致(默认都是int),可以把枚举值转成底层类型存储,简化遍历逻辑:
步骤1:定义统一底层类型和合并范围
#include <array> #include <type_traits> namespace regs { // 获取所有枚举的通用底层类型 using RegUnderlyingType = std::common_type_t< std::underlying_type_t<Control_0>, std::underlying_type_t<Control_1> >; // 转成底层类型后存入统一范围 constexpr std::array<RegUnderlyingType, 5> regs_range = { static_cast<RegUnderlyingType>(Control_0::THING1), static_cast<RegUnderlyingType>(Control_0::THING2), static_cast<RegUnderlyingType>(Control_0::THING3), static_cast<RegUnderlyingType>(Control_1::THING_A), static_cast<RegUnderlyingType>(Control_1::THING_B) }; }
步骤2:遍历并转换回原枚举类型
int main() { for (auto val : regs::regs_range) { // 根据值的范围判断所属枚举,转回去调用getThingData if (val <= static_cast<regs::RegUnderlyingType>(regs::Control_0::THING3)) { getThingData(static_cast<regs::Control_0>(val)); } else { getThingData(static_cast<regs::Control_1>(val)); } } return 0; }
优化:自动生成枚举值列表(减少手动维护)
如果你的枚举值是连续的,可以给每个枚举加上BEGIN和END标记,用模板自动生成值列表,避免手动逐个添加:
#include <vector> namespace regs { enum class Control_0 { BEGIN, THING1 = BEGIN, THING2, THING3, END }; enum class Control_1 { BEGIN, THING_A = BEGIN, THING_B, END }; // 模板函数:自动生成连续枚举的所有值 template <typename Enum> constexpr auto generate_enum_values() { std::vector<Enum> values; for (Enum e = Enum::BEGIN; e != Enum::END; e = static_cast<Enum>(static_cast<std::underlying_type_t<Enum>>(e) + 1)) { values.push_back(e); } return values; } // 生成每个枚举的自动列表 constexpr auto control_0_values = generate_enum_values<Control_0>(); constexpr auto control_1_values = generate_enum_values<Control_1>(); // 合并成变体范围 constexpr auto regs_range = [](){ std::vector<RegVariant> vec; vec.reserve(control_0_values.size() + control_1_values.size()); for (auto e : control_0_values) vec.push_back(e); for (auto e : control_1_values) vec.push_back(e); return vec; }(); }
这样后续新增枚举值时,只要调整END的位置,自动生成列表就会更新,不用手动修改范围内容。
内容的提问来源于stack exchange,提问作者eklund
相关产品推荐
相关产品推荐

