dimanche 24 avril 2022

How to use reflection to do the assignment for all kinds of fields

I'm working with Protobuf3 in a C++14 project.

Let's say that I have such a proto file:

syntax="proto3";
package srv.user;

option cc_generic_services = true;

message TestReq {
    uint32 seqid = 1;
    repeated uint64 userids = 2;
    map<string, string> infos = 3; 
};

message TestRes {
    uint32 resCode = 1;
};

service UserService {
    rpc RpcTest(TestReq) returns (TestRes);
};

Now, in my C++ project, I do

void func(const std::vector<uint64_t>& vec, const std::map<std::string, std::string>& mp) {
    srv::user::TestReq req;
    // use reflection to set each field of req
    const google::protobuf::Reflection* ref = req.GetReflection();
    const google::protobuf::Descriptor* des = req.GetDescriptor();
    initReq(ref, des, vec, mp, "seqid", "userids", "infos");
    ...
    ...
}

void initReq(const google::protobuf::Reflection* ref, const google::protobuf::Descriptor* des, const std::vector<uint64_t>& vec, const std::map<std::string, std::string>& mp, const std::string& fieldName1, const std::string& fieldName2, const std::string& fieldName3) {
    const google::protobuf::FieldDescriptor* fdes = nullptr;
    fdes = des->FindFieldByName("fieldName1");
    google::protobuf::Message* msg1 = ref->MutableMessage(req, fdes);
    *msg1 = 12345; // ERROR!
    fdes = des->FindFieldByName("fieldName2");
    google::protobuf::Message* msg2 = ref->MutableMessage(req, fdes);
    *msg2 = {vec.begin(), vec.end()}; // ERROR!
    fdes = des->FindFieldByName("fieldName3");
    google::protobuf::Message* msg3 = ref->MutableMessage(req, fdes);
    *msg3 = {mp.begin(), mp.end()}; // ERROR!
}

This won't work. Because msg1, msg2 and msg3 are all Message*. Meaning that I lost their real types in the function initReq.

Can we get the real type of google::protobuf::Message in the function initReq?





Aucun commentaire:

Enregistrer un commentaire