使用反射处理protobuf数据结构
google的protobuf是一種輕便高效的結(jié)構(gòu)化數(shù)據(jù)存儲(chǔ)格式,在通信協(xié)議和數(shù)據(jù)存儲(chǔ)等領(lǐng)域中使用比較多。protobuf對(duì)于結(jié)構(gòu)中的每個(gè)成員,會(huì)提供set系列函數(shù)和get系列函數(shù)。
但是,對(duì)于使用來說,需要根據(jù)傳入的參數(shù)考慮需要調(diào)用的函數(shù)名,在使用這個(gè)比較多的情況,還是會(huì)讓人覺得有些麻煩。而且,對(duì)于有些使用,例如之后打算不再使用protobuf,改為直接將數(shù)據(jù)壓入內(nèi)存段(The raw in-memory data structures sent/saved in binary form),或者直接壓入內(nèi)存段的方式,改為使用protobuf,那么,如果兩者都是通過傳入函數(shù)的方式來進(jìn)行數(shù)據(jù)設(shè)置,或者數(shù)據(jù)解析,那么改動(dòng)內(nèi)容會(huì)比較少,而且出錯(cuò)幾率也會(huì)比較低。那么如何實(shí)現(xiàn)呢?
先給出proto文件:
?
syntax = "proto2";package student;message Student {required string name = 1;required int32 id = 2;optional int32 age = 3;optional string phoneNumber = 4; }下面給出通過函數(shù)重載方式,來處理各種參數(shù)類型的方式:
#include <google\protobuf\message.h>namespace goo_proto = ::google::protobuf;template <typename Param> struct ProtoFunc {static constexpr void* SetValueFunc = nullptr; };template <> struct ProtoFunc<goo_proto::int32> {static constexpr auto SetValueFunc = &(goo_proto::Reflection::SetInt32); };template <> struct ProtoFunc<goo_proto::int64> {static constexpr auto SetValueFunc = &(goo_proto::Reflection::SetInt64); };template <> struct ProtoFunc<std::string> {static constexpr auto SetValueFunc = &(goo_proto::Reflection::SetString); };template <> struct ProtoFunc<const char*> {static constexpr auto SetValueFunc = &(goo_proto::Reflection::SetString); };template <typename ValueType> void SetFieldValue(goo_proto::Message* msg, const goo_proto::Reflection* reflection,const goo_proto::FieldDescriptor* field, ValueType&& value) {(reflection->*(ProtoFunc<std::remove_cv_t<std::decay_t<ValueType>>>::SetValueFunc))(msg, field, std::forward<ValueType>(value)); }通過上述的模板,就可以調(diào)用SetFieldValue來處理int32, int64, std::string和const char*了,這個(gè)是實(shí)現(xiàn)泛型函數(shù)的前期準(zhǔn)備。
下面給出一次設(shè)置多個(gè)參數(shù)的方式:
template <typename ...Args> void SetFieldAllValues(goo_proto::Message* msg, Args&&... args) {auto descriptor = msg->GetDescriptor();auto reflection = msg->GetReflection();SetFieldImpl<0>(msg, descriptor, reflection, std::forward<Args>(args)...); }template <size_t idx, typename T, typename ...Args> void SetFieldImpl(goo_proto::Message* msg, const goo_proto::Descriptor* descriptor, const goo_proto::Reflection* reflection,T&& value, Args&&... args) {auto field = descriptor->field(idx);SetFieldValue(msg, reflection, field, std::forward<T>(value));SetFieldImpl<idx + 1>(msg, descriptor, reflection, std::forward<Args>(args)...); }template <size_t idx> void SetFieldImpl(goo_proto::Message* msg, const goo_proto::Descriptor* descriptor, const goo_proto::Reflection* reflection) {// empty }上面就是實(shí)現(xiàn),設(shè)置所有proto結(jié)構(gòu)體中元素的方式。多謝protobuf中提供了descriptor::field函數(shù),通過這個(gè)函數(shù),我才有辦法比較簡(jiǎn)單的實(shí)現(xiàn)通過傳入所有的參數(shù)(這里沒有考慮設(shè)置repeat成員),來一次性設(shè)置好整個(gè)proto結(jié)構(gòu)體對(duì)象。下面看一下使用上述函數(shù)的一個(gè)實(shí)例:
#include <iostream> #include <string> #include "studentinfo.h" #include "studentinfo.pb.h"int main(int argc, char* argv[]) {student::Student s;SetFieldAllValues(&s, "Jack", 10, 20, "11122233345");std::cout << s.name() << std::endl;std::cout << s.id() << std::endl;std::cout << s.age() << std::endl;std::cout << s.phonenumber() << std::endl;return 0; }這里只是提供了設(shè)置的函數(shù)(Set函數(shù)),沒有提供Get函數(shù),不過根據(jù)類似的方式,實(shí)現(xiàn)Get函數(shù)應(yīng)該不是很困難,這里就不給出代碼了。
轉(zhuǎn)載于:https://www.cnblogs.com/albizzia/p/9153252.html
總結(jié)
以上是生活随笔為你收集整理的使用反射处理protobuf数据结构的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【转载】最大权闭合子图 【网络流】
- 下一篇: redis入门demo