实现爆炸猫游戏时,如何用RapidJSON获取enum class枚举值?
问题
我正在实现Exploding Kittens(爆炸猫)卡牌游戏,将卡牌类型定义为如下enum class:
enum class card_type { Kitten, Bomb, ... }
并将其作为私有变量card_type* value使用。后续在通过JSON传递事件时,希望使用RapidJSON从JSON中获取该枚举值。
我编写了如下from_json模板函数:
static serializable_value<T>* from_json(const rapidjson::Value& json) { if (json.HasMember("value")) { T val = json["value"].Get<T>(); return new serializable_value<T>(val); } return nullptr; }
并通过以下方式调用:
serializable_value<card_type>::from_json(json["value"].GetObject())
其中serializable_value是用于处理JSON的辅助类。
当使用int* value并调用serializable_value<int>::from_json(json["value"].GetObject())时代码运行正常,但使用enum class时出现报错,完整栈跟踪如下:
error: no member named 'Get' in 'rapidjson::internal::TypeHelper<rapidjson::GenericValue<rapidjson::UTF8<> >, card_type>' T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); } ^ /src/common/game_state/cards/../../serialization/serializable_value.h:52:35: note: in instantiation of function template specialization 'rapidjson::GenericValue<rapidjson::UTF8<> >::Get<card_type>' requested here T val = json["value"].Get<T>(); ^ /src/common/game_state/cards/card.cpp:35:80: note: in instantiation of member function 'serializable_value<card_type>::from_json' requested here return new card(json["id"].GetString(), serializable_value<card_type>::from_json(json["value"].GetObject()));
请问该如何处理这种本质为无符号整数的enum class类型?
解决方法
RapidJSON的Get<T>()模板默认不支持C++11的强类型枚举(enum class),因为强类型枚举不能隐式转换为整数类型。针对这个问题,有两种常用的处理方式:
方式一:手动转换整数到枚举类型
修改from_json函数,先把JSON中的值取为对应的整数类型,再显式转换为card_type。借助std::underlying_type_t<T>可以自动获取枚举的底层整数类型,不用硬编码类型,更通用:
#include <type_traits> // 需要包含此头文件 static serializable_value<T>* from_json(const rapidjson::Value& json) { if (json.HasMember("value")) { using UnderlyingType = std::underlying_type_t<T>; UnderlyingType int_val = json["value"].Get<UnderlyingType>(); T val = static_cast<T>(int_val); return new serializable_value<T>(val); } return nullptr; }
方式二:为RapidJSON特化TypeHelper模板
如果希望保持原有Get<T>()的调用方式不变,可以为card_type特化RapidJSON内部的TypeHelper模板,让它支持直接获取枚举值:
#include <type_traits> namespace rapidjson { namespace internal { template<> struct TypeHelper<GenericValue<UTF8<> >, card_type> { static card_type Get(const GenericValue<UTF8<> >& v) { using UnderlyingType = std::underlying_type_t<card_type>; return static_cast<card_type>(v.Get<UnderlyingType>()); } }; } // namespace internal } // namespace rapidjson
特化完成后,原来的Get<card_type>()调用就能正常工作,无需修改from_json函数。
注意事项
- 确保JSON中存储的数值与
card_type定义的底层整数取值完全匹配,避免转换后出现无效的枚举值。 - 两种方式都需要包含
<type_traits>头文件以使用std::underlying_type_t。
内容的提问来源于stack exchange,提问作者Alex
相关产品推荐
相关产品推荐

