如何实现无需显式指定类型的input_action结构体get_data()函数
解决方案:基于C++特性实现自动类型匹配的get_data()
首先先明确你的结构体与枚举的典型定义(补全常见结构):
enum class input_value { _bool, _int, _float }; union input_action_data { bool b; int i; float f; }; struct input_action { input_value type; input_action_data data; };
方案1:C++17 constexpr if 实现(最简洁)
利用编译期分支判断,只保留匹配类型的代码逻辑,解决模板实例化时的类型冲突问题:
#include <type_traits> #include <cassert> struct input_action { input_value type; input_action_data data; template<typename T> T get_data() const { // 限制支持的类型,避免非法类型调用 static_assert(std::is_same_v<T, bool> || std::is_same_v<T, int> || std::is_same_v<T, float>, "Unsupported data type for get_data()"); if constexpr (std::is_same_v<T, bool>) { assert(type == input_value::_bool && "Type mismatch: requested bool but stored type is different"); return data.b; } else if constexpr (std::is_same_v<T, int>) { assert(type == input_value::_int && "Type mismatch: requested int but stored type is different"); return data.i; } else if constexpr (std::is_same_v<T, float>) { assert(type == input_value::_float && "Type mismatch: requested float but stored type is different"); return data.f; } } };
使用时无需显式指定模板参数,编译器会根据接收变量的类型自动推导:
input_action action; action.type = input_value::_bool; action.data.b = true; bool val = action.get_data(); // 自动推导T为bool,正常返回
方案2:兼容C++11/14的标签分发方案
如果项目无法使用C++17,可通过标签类型重载实现:
#include <stdexcept> #include <cassert> // 定义类型标签 struct bool_tag {}; struct int_tag {}; struct float_tag {}; // 根据枚举获取对应标签 constexpr auto get_tag(input_value type) { switch(type) { case input_value::_bool: return bool_tag{}; case input_value::_int: return int_tag{}; case input_value::_float: return float_tag{}; default: throw std::invalid_argument("Invalid input_value type"); } } // 重载不同标签的实现函数 bool get_data_impl(const input_action_data& data, bool_tag) { return data.b; } int get_data_impl(const input_action_data& data, int_tag) { return data.i; } float get_data_impl(const input_action_data& data, float_tag) { return data.f; } struct input_action { input_value type; input_action_data data; // 利用auto推导返回类型(C++14支持) auto get_data() const { assert(type != input_value{} && "Uninitialized input_value type"); return get_data_impl(data, get_tag(type)); } };
使用时返回值类型会自动匹配枚举标记的存储类型:
input_action action; action.type = input_value::_float; action.data.f = 3.14f; auto val = action.get_data(); // val的类型为float
问题根源解析
你之前的模板写法失效,是因为模板函数实例化时会检查所有分支的代码合法性——哪怕运行时不会走到某分支,编译器也会要求该分支的类型转换合法。而constexpr if会在编译期直接丢弃不匹配的分支,标签分发则通过重载让编译器只选择对应类型的实现,从根本上避免了类型冲突。
内容的提问来源于stack exchange,提问作者Mich
相关产品推荐
相关产品推荐

