Search code examples
c++protocol-bufferscopy-constructor

How to set two similar msg's attributes with less duplicate codes in C++?


How to set variable properties use less duplicate code in C++?

A.proto

syntax = "proto3";

package Test1;

message A{
    double x = 1;
    double y = 2;
    double z = 3;
    double theta = 4;
    double kappa = 5;
    float s = 6;
    float v = 7;
    float a = 8;
}

B.proto

syntax = "proto3";

package Test2;

message A{
    double x = 1;
    double y = 2;
    double z = 3;
    double theta = 4;
    double kappa = 5;
    float s = 6;
    float v = 7;
    float a = 8;
}

main

#include <iostream>
#include "A.pb.h"
#include "B.pb.h"

void fun(){
    Test1::A t1;
    Test2::A t2;
    // t1's assignment, no need to care
    t1.set_x(1.0);
    t1.set_y(2.0);
    t1.set_z(3.0);
    t1.set_theta(4.0);
    t1.set_kappa(5.0);
    t1.set_s(6.0);
    t1.set_v(7.0);
    t1.set_a(8.0);

    // t2 = static_cast<Test2::A>(t1); can't cast

    // t2's assignment by t1
    // Is there any other ways set t2 by t1's attribute?
    t2.set_x(t1.x());
    t2.set_y(t1.y());
    t2.set_z(t1.z());
    t2.set_theta(t1.theta());
    t2.set_kappa(t1.kappa());
    t2.set_s(t1.s());
    t2.set_v(t1.v());
    t2.set_a(t1.a());
    
    // something about t2....
    std::cout << t2.z() << std::endl;
}

int main(){
    fun();
}

two msgs defined by proto above, their attributes are almost the same except NAMESPACE, due to some reasons,their namespace CANNOT be changed.So is there any other ways set t2 by t1's attribute?


Solution

  • The best way is to redesign your protos, and put those common attributes into a message, and refer this message in both Test1::A and Test2::A with import.

    package util;
    
    message Common {
       // fileds...
    }
    
    package Test1;
    message A {
      util::Common attr = 1;
    }
    
    package Test2;
    message A {
      util::Common attr = 1;
    }
    
    Test1::A t1;
    // set t1.attr.xxx
    
    Test2::A t2;
    // copy common attr
    *(t2.mutable_attr()) = t1.attr();
    

    Since Test1::A and Test2::A is exactly the same, there's another solution which is less performant, and you don't need to change the proto definition: serialize t1 to string, and construct t2 with the serialized string.

    string s;
    t1.SerializeToString(&s);
    t2.ParseFromString(s);