如何用现代C++重构联合成员的嵌套switch语句
用现代C++重构嵌套switch的联合类型操作代码
问题描述
现有C++代码通过枚举、联合和结构体实现动态类型值的加法操作,核心代码如下:
enum Value_type_id { i, f, d }; union Value { int i; float f; double d; }; struct Item { Value_type_id type; Value value; }; Item add(Item lhs, Item rhs) { Item result; switch (lhs.type) { case i: switch (rhs.type) { case i: result.type = i; result.value.i = lhs.value.i + rhs.value.i; break; case f: result.type = f; result.value.f = lhs.value.i + rhs.value.f; break; case d: result.type = d; result.value.d = lhs.value.i + rhs.value.d; break; } break; case f: switch (rhs.type) { case i: result.type = f; result.value.f = lhs.value.f + rhs.value.i; break; case f: result.type = f; result.value.f = lhs.value.f + rhs.value.f; break; case d: result.type = d; result.value.d = lhs.value.f + rhs.value.d; break; } break; case d: switch (rhs.type) { case i: result.type = d; result.value.d = lhs.value.d + rhs.value.i; break; case f: result.type = d; result.value.d = lhs.value.d + rhs.value.f; break; case d: result.type = d; result.value.d = lhs.value.d + rhs.value.d; break; } break; } return result; }
需求是彻底消除重复的嵌套switch语句,希望实现类似如下的简洁调用:
Item add(Item lhs, Item rhs) { return some_magic_here(std::plus{}, lhs, rhs); }
实际场景需要处理8种数据类型,若沿用现有写法会产生64个重复case,维护成本极高。
补充说明
- 应用是规模达17万行的独立解释型语言,当前全程使用上述枚举/联合/结构体结构,仅在能显著消除重复代码时才考虑重构。
- 后续还需要针对向量类型实现类似的解决方案,但暂时不知如何扩展现有方案。
解决方案
我们可以通过模板元编程+类型映射的方式,将枚举类型与实际C++类型绑定,自动生成类型分发逻辑,彻底消除嵌套switch,同时保留原有Item结构无需大规模重构。
步骤1:定义类型映射与辅助工具
首先创建枚举到类型的双向映射,以及提取值、构造Item的辅助函数:
#include <type_traits> #include <functional> #include <tuple> // 保留原有枚举定义 enum Value_type_id { i, f, d }; union Value { int i; float f; double d; }; struct Item { Value_type_id type; Value value; }; // 枚举到C++类型的映射模板 template<Value_type_id> struct type_from_id; template<> struct type_from_id<i> { using type = int; }; template<> struct type_from_id<f> { using type = float; }; template<> struct type_from_id<d> { using type = double; }; // C++类型到枚举的映射模板 template<typename T> struct id_from_type; template<> struct id_from_type<int> { static constexpr Value_type_id value = i; }; template<> struct id_from_type<float> { static constexpr Value_type_id value = f; }; template<> struct id_from_type<double> { static constexpr Value_type_id value = d; }; // 简化类型别名 template<Value_type_id Id> using type_from_id_t = typename type_from_id<Id>::type; template<typename T> constexpr Value_type_id id_from_type_v = id_from_type<T>::value; // 从Item中提取对应类型的值(类型安全的强制转换) template<Value_type_id Id> constexpr type_from_id_t<Id>& get_value(Item& item) { return reinterpret_cast<type_from_id_t<Id>&>(item.value); } template<Value_type_id Id> constexpr const type_from_id_t<Id>& get_value(const Item& item) { return reinterpret_cast<const type_from_id_t<Id>&>(item.value); } // 从原始值构造Item template<typename T> constexpr Item make_item(T&& val) { Item item; using DecayedT = std::decay_t<T>; item.type = id_from_type_v<DecayedT>; get_value<id_from_type_v<DecayedT>>(item) = std::forward<T>(val); return item; }
步骤2:实现通用分发函数some_magic_here
编写核心分发逻辑,利用编译期生成的类型列表自动处理所有类型组合:
// 编译期类型列表,后续扩展类型只需添加到元组中 using TypeList = std::tuple<int, float, double>; namespace detail { // 递归遍历所有类型组合的辅助函数 template<typename Func, typename LhsType, typename... RestLhs, typename... RhsTypes> constexpr Item dispatch_lhs(Func&& func, const Item& lhs, const Item& rhs, std::tuple<LhsType, RestLhs...>, std::tuple<RhsTypes...>) { if (lhs.type == id_from_type_v<LhsType>) { // 匹配左值类型后,遍历右值类型 return ((rhs.type == id_from_type_v<RhsTypes>) ? make_item(std::invoke(std::forward<Func>(func), get_value<id_from_type_v<LhsType>>(lhs), get_value<id_from_type_v<RhsTypes>>(rhs))) : dispatch_lhs(std::forward<Func>(func), lhs, rhs, std::tuple<RestLhs...>{}, std::tuple<RhsTypes...>{})); } return dispatch_lhs(std::forward<Func>(func), lhs, rhs, std::tuple<RestLhs...>{}, std::tuple<RhsTypes...>{}); } // 终止递归的特化 template<typename Func, typename... RhsTypes> constexpr Item dispatch_lhs(Func&&, const Item&, const Item&, std::tuple<>, std::tuple<RhsTypes...>) { // 理论上不会走到这里,除非传入非法类型的Item return {}; } } // 对外暴露的通用分发函数 template<typename Func> constexpr Item some_magic_here(Func&& func, const Item& lhs, const Item& rhs) { return detail::dispatch_lhs(std::forward<Func>(func), lhs, rhs, TypeList{}, TypeList{}); }
步骤3:简洁实现加法函数
现在只需一行代码即可实现add函数,完全无需嵌套switch:
Item add(Item lhs, Item rhs) { return some_magic_here(std::plus{}, lhs, rhs); }
扩展说明
- 新增基础类型:只需在
Value_type_id中添加枚举值,补充type_from_id和id_from_type的特化模板,再将新类型加入TypeList元组即可。 - 扩展向量类型:将向量类型(如
std::vector<int>)加入类型映射,调整get_value和make_item的实现以适配向量的存储逻辑,核心分发逻辑无需修改。
内容的提问来源于stack exchange,提问作者Louis Strous
相关产品推荐
相关产品推荐

