如何自动实现C++结构体与google::protobuf::Struct的双向转换?
自动将C++结构体转换为google::protobuf::Struct的方案
针对你60余个嵌套C++结构体的转换需求,以下三种自动化方案可替代手动填充逻辑:
方法1:模板元编程+手动添加元信息
利用C++17的结构化绑定与std::apply,仅需为每个结构体定义成员元信息,即可自动生成转换逻辑,性能无额外开销。
步骤1:实现基本类型到protobuf Value的填充函数
#include <google/protobuf/struct.pb.h> #include <tuple> #include <string> // 基本类型转google::protobuf::Value void fill_value(int32_t val, google::protobuf::Value& value) { value.set_number_value(val); } void fill_value(const std::string& val, google::protobuf::Value& value) { value.set_string_value(val); } void fill_value(bool val, google::protobuf::Value& value) { value.set_bool_value(val); } // 自定义结构体转Struct后包装成Value template<typename T> void fill_value(const T& obj, google::protobuf::Value& value) { auto* struct_val = value.mutable_struct_value(); convert_to_proto_struct(obj, *struct_val); }
步骤2:为每个结构体定义成员元信息
创建模板结构体StructMembers,为目标结构体提供成员名称与成员指针的tuple:
// 声明模板结构体 template<typename T> struct StructMembers; // 特化Object1的元信息 template<> struct StructMembers<Object1> { static constexpr auto value = std::make_tuple( std::pair{"member1", &Object1::member1}, std::pair{"member2", &Object1::member2}, std::pair{"member3", &Object1::member3} ); }; // 特化Object2的元信息 template<> struct StructMembers<Object2> { static constexpr auto value = std::make_tuple( std::pair{"member1", &Object2::member1}, std::pair{"member2", &Object2::member2}, std::pair{"member3", &Object2::member3} ); };
步骤3:通用转换函数
通过std::apply遍历成员元信息,自动填充protobuf Struct:
template<typename T> void convert_to_proto_struct(const T& obj, google::protobuf::Struct& proto_struct) { auto* fields = proto_struct.mutable_fields(); // 遍历tuple中所有成员并填充 std::apply([&](auto&&... members) { ( [&]() { const auto& [name, member_ptr] = members; google::protobuf::Value value; fill_value(obj.*member_ptr, value); (*fields)[name] = std::move(value); }(), ... ); }, StructMembers<T>::value); }
使用示例:
Object1 my_obj; // 填充my_obj数据... google::protobuf::Struct proto_struct; convert_to_proto_struct(my_obj, proto_struct);
方法2:代码生成工具(适合大量结构体)
若结构体数量超过60个,手动写模板特化仍繁琐,可通过代码生成工具批量生成转换逻辑。
核心思路
- 用
pycparser或Clang LibTooling解析C++头文件,提取结构体的成员名与类型。 - 自动生成对应结构体的
convert_to_proto_struct函数,自动处理基本类型与嵌套结构体。
生成的代码示例:
void convert_to_proto_struct(const Object2& obj, google::protobuf::Struct& proto_struct) { auto* fields = proto_struct.mutable_fields(); { google::protobuf::Value val; val.set_number_value(obj.member1); (*fields)["member1"] = val; } { google::protobuf::Value val; val.set_string_value(obj.member2); (*fields)["member2"] = val; } { google::protobuf::Value val; val.set_bool_value(obj.member3); (*fields)["member3"] = val; } } void convert_to_proto_struct(const Object1& obj, google::protobuf::Struct& proto_struct) { auto* fields = proto_struct.mutable_fields(); { google::protobuf::Value val; val.set_number_value(obj.member1); (*fields)["member1"] = val; } { google::protobuf::Value val; val.set_string_value(obj.member2); (*fields)["member2"] = val; } { google::protobuf::Value val; convert_to_proto_struct(obj.member3, *val.mutable_struct_value()); (*fields)["member3"] = val; } }
方法3:JSON中转(快速实现)
借助nlohmann/json库将C++结构体序列化为JSON,再转换为google::protobuf::Struct,代码量最少,适合对性能要求不高的场景。
步骤1:依赖nlohmann/json并添加序列化支持
#include <nlohmann/json.hpp> using json = nlohmann::json; // 为结构体添加序列化宏 NLOHMANN_DEFINE_TYPE_INTRUSIVE(Object1, member1, member2, member3) NLOHMANN_DEFINE_TYPE_INTRUSIVE(Object2, member1, member2, member3)
步骤2:实现JSON到protobuf Struct的转换
void json_to_proto_struct(const json& j, google::protobuf::Struct& proto_struct) { auto* fields = proto_struct.mutable_fields(); for (const auto& [key, val] : j.items()) { google::protobuf::Value proto_val; if (val.is_number_integer()) { proto_val.set_number_value(val.get<int64_t>()); } else if (val.is_number_float()) { proto_val.set_number_value(val.get<double>()); } else if (val.is_string()) { proto_val.set_string_value(val.get<std::string>()); } else if (val.is_boolean()) { proto_val.set_bool_value(val.get<bool>()); } else if (val.is_object()) { json_to_proto_struct(val, *proto_val.mutable_struct_value()); } else if (val.is_array()) { // 如需处理数组可扩展此处逻辑 auto* list_val = proto_val.mutable_list_value(); for (const auto& elem : val) { google::protobuf::Value elem_val; json_to_proto_struct(elem, *elem_val.mutable_struct_value()); *list_val->add_values() = std::move(elem_val); } } (*fields)[key] = std::move(proto_val); } }
使用示例:
Object1 my_obj; // 填充数据... json j = my_obj; google::protobuf::Struct proto_struct; json_to_proto_struct(j, proto_struct);
内容的提问来源于stack exchange,提问作者Saransh
相关产品推荐
相关产品推荐

