如何在C++17中泛化std::conditional_t适配多枚举类型?
问题描述
我有一个根据给定参数计算特定对象的函数(比如从图中提取重要节点)。计算过程中可能会分配内存,有时候我只需要返回计算结果,有时候希望同时返回结果和计算所用的内存。
针对这种二元场景,我之前是这么实现的:
enum class what { what1, // 返回值类型:int what2 // 返回值类型:std::pair<int, std::vector<int>> }; template <what w> std::conditional_t<w == what::what1, int, std::pair<int, std::vector<int>>> calculate_something(const param& p) { ... }
现在我想把这个方案扩展到更多选项的枚举类型:
enum class list_whats { what1, what2, what3, what4, what5 };
一种可行的方式是嵌套多个std::conditional_t:
template <list_whats what> std::conditional_t< what == list_whats::what1, int, std::conditional_t< what == list_whats::what2, float, .... > > calculate_something(const param& p) { ... }
但这种写法太繁琐,不够优雅。有没有更简洁的C++17实现方式?
补充说明
需要实现return_something函数,使得下面的main函数可以正常编译运行:
int main() { int s1 = return_something<list_whats::what1>(); s1 = 3; float s2 = return_something<list_whats::what2>(); s2 = 4.0f; double s3 = return_something<list_whats::what3>(); s3 = 9.0; std::string s4 = return_something<list_whats::what4>(); s4 = "qwer"; std::vector<int> s5 = return_something<list_whats::what5>(); s5[3] = 25; }
解决方案
方案一:模板特化(直观易维护)
针对每个枚举值单独特化函数,每个分支可以实现独立的计算逻辑:
#include <string> #include <vector> enum class list_whats { what1, what2, what3, what4, what5 }; // 主模板声明 template <list_whats What> auto return_something(); // 特化每个枚举对应的返回类型和实现 template <> auto return_something<list_whats::what1>() { return int{}; // 替换为实际计算逻辑 } template <> auto return_something<list_whats::what2>() { return float{}; } template <> auto return_something<list_whats::what3>() { return double{}; } template <> auto return_something<list_whats::what4>() { return std::string{}; } template <> auto return_something<list_whats::what5>() { return std::vector<int>{4}; // 初始化大小为4,适配main中的s5[3]操作 } // 测试代码 int main() { int s1 = return_something<list_whats::what1>(); s1 = 3; float s2 = return_something<list_whats::what2>(); s2 = 4.0f; double s3 = return_something<list_whats::what3>(); s3 = 9.0; std::string s4 = return_something<list_whats::what4>(); s4 = "qwer"; std::vector<int> s5 = return_something<list_whats::what5>(); s5[3] = 25; }
方案二:编译期类型映射表(集中管理对应关系)
用std::tuple集中管理枚举和返回类型的映射,适合计算逻辑有共性的场景:
#include <string> #include <vector> #include <tuple> #include <type_traits> enum class list_whats { what1, what2, what3, what4, what5 }; // 枚举与返回类型的映射表,顺序和枚举值一一对应 using ReturnTypeMap = std::tuple<int, float, double, std::string, std::vector<int>>; // 辅助工具:将枚举值转换为tuple的索引 template <list_whats What> constexpr size_t EnumToIndex() { return static_cast<size_t>(What); } // 主函数模板,根据索引获取对应返回类型 template <list_whats What> std::tuple_element_t<EnumToIndex<What>(), ReturnTypeMap> return_something() { using ReturnType = std::tuple_element_t<EnumToIndex<What>(), ReturnTypeMap>; // 统一或分支处理计算逻辑 if constexpr (std::is_same_v<ReturnType, std::vector<int>>) { return ReturnType{4}; // 适配main中的s5[3]操作 } else { return ReturnType{}; } } // 测试代码 int main() { int s1 = return_something<list_whats::what1>(); s1 = 3; float s2 = return_something<list_whats::what2>(); s2 = 4.0f; double s3 = return_something<list_whats::what3>(); s3 = 9.0; std::string s4 = return_something<list_whats::what4>(); s4 = "qwer"; std::vector<int> s5 = return_something<list_whats::what5>(); s5[3] = 25; }
方案对比
- 模板特化:每个枚举值的实现完全独立,适合不同返回类型需要差异化计算逻辑的场景,代码直观,易调试维护。
- 编译期映射表:枚举与类型的对应关系集中管理,新增枚举值只需修改映射表和初始化逻辑,适合返回类型与枚举一一对应且计算逻辑有共性的场景。
内容的提问来源于stack exchange,提问作者llualpu
相关产品推荐
相关产品推荐

