You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何自动实现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个,手动写模板特化仍繁琐,可通过代码生成工具批量生成转换逻辑。

核心思路

  1. 用pycparser或Clang LibTooling解析C++头文件,提取结构体的成员名与类型。
  2. 自动生成对应结构体的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.14 11:41:07