在C++中如何将枚举类型引用转换为其底层类型的引用?
问题描述
我正在开发反序列化器,项目里有大量枚举类型,不想为每个枚举都编写deserialize重载函数,尝试将枚举类型的引用转换为其底层类型的引用,但代码无法编译,代码如下:
#include <iostream> #include <cstdint> #include <type_traits> #include <cstring> enum class MyEnum : uint32_t { one = 100, two, }; auto deserialize(std::byte* addr, uint32_t& val) { memcpy(&val, addr, sizeof(uint32_t)); } int main() { std::byte buf[4] = { std::byte{0x00}, std::byte{0x00}, std::byte{0x00}, std::byte{0x64}}; MyEnum val; using underlying_type = std::underlying_type_t<decltype(val)>&; deserialize(buf, static_cast<underlying_type>(val)); std::cout << val << std::endl; }
解决方案
问题原因
直接通过static_cast将枚举对象转换为其底层类型的引用是不合法的——枚举类型与底层类型属于不同类型,C++不允许这种直接的引用转换,违反类型安全规则。
修复方式
方式一:指针转换(快速修复现有代码)
先获取枚举对象的地址,转换为底层类型指针后解引用得到引用,适配现有deserialize函数:
int main() { std::byte buf[4] = { std::byte{0x00}, std::byte{0x00}, std::byte{0x00}, std::byte{0x64}}; MyEnum val; using Underlying = std::underlying_type_t<decltype(val)>; // 先转void*避免严格别名问题,再转底层类型指针并解引用 deserialize(buf, *static_cast<Underlying*>(static_cast<void*>(&val))); // 强类型枚举不能直接输出,需转换为底层类型 std::cout << static_cast<Underlying>(val) << std::endl; }
方式二:通用模板函数(优雅解决大量枚举场景)
实现支持所有枚举类型的通用deserialize模板,从根源避免重复编写重载:
#include <iostream> #include <cstdint> #include <type_traits> #include <cstring> enum class MyEnum : uint32_t { one = 100, two, }; // 仅对枚举类型生效的模板函数 template<typename Enum, std::enable_if_t<std::is_enum_v<Enum>, bool> = true> void deserialize(std::byte* addr, Enum& val) { using Underlying = std::underlying_type_t<Enum>; memcpy(&val, addr, sizeof(Underlying)); } // 保留基础类型的重载(若有需要) void deserialize(std::byte* addr, uint32_t& val) { memcpy(&val, addr, sizeof(uint32_t)); } int main() { std::byte buf[4] = { std::byte{0x00}, std::byte{0x00}, std::byte{0x00}, std::byte{0x64}}; MyEnum val; deserialize(buf, val); // 直接传递枚举引用即可 std::cout << static_cast<std::underlying_type_t<MyEnum>>(val) << std::endl; }
这个模板用std::is_enum_v做约束,确保只处理枚举类型,内部直接通过memcpy将数据写入枚举对象的内存,安全且无需手动转换类型,新增枚举时无需修改反序列化逻辑。
内容的提问来源于stack exchange,提问作者glades
相关产品推荐
相关产品推荐

