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

C++20如何遍历以枚举为模板参数的成员函数?

枚举模板参数成员函数的自动遍历方案

1. 完善枚举定义

首先给fruit枚举添加一个表示总数量的枚举值,同时补充数值转枚举的辅助函数,为后续遍历提供基础:

struct fruit
{
  enum Value : uint8_t
  {
    apple,
    banana,
    kiwi,
    count // 新增:标记枚举值总数量
  };

  fruit() = default;
  fruit(Value afruit) : value(afruit) { }
  Value value;

  // 辅助:将索引值转换为对应的枚举值
  static constexpr Value from_index(uint8_t idx) { return static_cast<Value>(idx); }
};

2. 实现通用遍历逻辑

利用C++11的std::integer_sequence生成编译时索引序列,通过参数包展开自动调用每个枚举对应的模板成员函数:

#include <utility> // 引入std::integer_sequence

namespace detail {
// 内部实现:展开索引序列并执行操作
template <typename Obj, typename Func, std::size_t... Idx>
void for_each_fruit_impl(Obj& obj, Func&& func, std::integer_sequence<std::size_t, Idx...>)
{
    // 逗号表达式展开,对每个索引对应的枚举值执行传入的操作
    (func(obj, fruit::from_index(static_cast<uint8_t>(Idx))), ...);
}
} // namespace detail

// 对外接口:遍历所有fruit枚举值
template <typename Obj, typename Func>
void for_each_fruit(Obj& obj, Func&& func)
{
    using Seq = std::make_integer_sequence<std::size_t, static_cast<std::size_t>(fruit::count)>;
    detail::for_each_fruit_impl(obj, std::forward<Func>(func), Seq{});
}

3. 实际使用示例

遍历调用field::plant()

替换原来的手动逐个调用,用遍历逻辑自动处理所有枚举值:

int main(int argc, char** argv)
{
    auto f = field{};

    // 自动遍历所有fruit枚举值,调用对应的plant模板函数
    for_each_fruit(f, [](auto& obj, fruit::Value f_val) {
        if constexpr (f_val == fruit::apple) {
            obj.plant<fruit::apple>();
        } else if constexpr (f_val == fruit::banana) {
            obj.plant<fruit::banana>();
        } else if constexpr (f_val == fruit::kiwi) {
            obj.plant<fruit::kiwi>();
        }
    });

    // 针对带参数的barn::store()函数
    auto b = barn{};
    int arg = 42;
    for_each_fruit(b, [arg](auto& obj, fruit::Value f_val) {
        if constexpr (f_val == fruit::apple) {
            obj.store<fruit::apple>(arg);
        } else if constexpr (f_val == fruit::banana) {
            obj.store<fruit::banana>(arg);
        } else if constexpr (f_val == fruit::kiwi) {
            obj.store<fruit::kiwi>(arg);
        }
    });

    return 0;
}

4. 优化:简化枚举值与模板参数的匹配

如果觉得每个枚举值写if constexpr繁琐,可以封装通用调用函数,直接映射枚举值到模板参数:

// 针对plant函数的通用调用
template <fruit::Value F, typename Obj>
void call_plant(Obj& obj)
{
    if constexpr (F == fruit::apple) {
        obj.template plant<fruit::apple>();
    } else if constexpr (F == fruit::banana) {
        obj.template plant<fruit::banana>();
    } else if constexpr (F == fruit::kiwi) {
        obj.template plant<fruit::kiwi>();
    }
}

// 针对store函数的通用调用
template <fruit::Value F, typename Obj, typename... Args>
void call_store(Obj& obj, Args&&... args)
{
    if constexpr (F == fruit::apple) {
        obj.template store<fruit::apple>(std::forward<Args>(args)...);
    } else if constexpr (F == fruit::banana) {
        obj.template store<fruit::banana>(std::forward<Args>(args)...);
    } else if constexpr (F == fruit::kiwi) {
        obj.template store<fruit::kiwi>(std::forward<Args>(args)...);
    }
}

之后遍历代码可以简化为:

// 调用plant
for_each_fruit(f, [](auto& obj, fruit::Value f_val) {
    call_plant<f_val>(obj);
});

// 调用store
for_each_fruit(b, [arg](auto& obj, fruit::Value f_val) {
    call_store<f_val>(obj, arg);
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 09:25:13