google的protobuf是一种轻便高效的结构化数据存储格式,在通信协议和数据存储等领域中使用比较多。protobuf对于结构中的每个成员,会提供set系列函数和get系列函数。

但是,对于使用来说,需要根据传入的参数考虑需要调用的函数名,在使用这个比较多的情况,还是会让人觉得有些麻烦。而且,对于有些使用,例如之后打算不再使用protobuf,改为直接将数据压入内存段(The raw in-memory data structures sent/saved in binary form),或者直接压入内存段的方式,改为使用protobuf,那么,如果两者都是通过传入函数的方式来进行数据设置,或者数据解析,那么改动内容会比较少,而且出错几率也会比较低。那么如何实现呢?

先给出proto文件:

syntax = "proto2";

package student;

message Student
{
required string name = ;
required int32 id = ;
optional int32 age = ;
optional string phoneNumber = ;
}

下面给出通过函数重载方式,来处理各种参数类型的方式:

#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));
}

通过上述的模板,就可以调用SetFieldValue来处理int32, int64, std::string和const char*了,这个是实现泛型函数的前期准备。

下面给出一次设置多个参数的方式:

template <typename ...Args>
void SetFieldAllValues(goo_proto::Message* msg, Args&&... args)
{
auto descriptor = msg->GetDescriptor();
auto reflection = msg->GetReflection();
SetFieldImpl<>(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 + >(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
}

上面就是实现,设置所有proto结构体中元素的方式。多谢protobuf中提供了descriptor::field函数,通过这个函数,我才有办法比较简单的实现通过传入所有的参数(这里没有考虑设置repeat成员),来一次性设置好整个proto结构体对象。下面看一下使用上述函数的一个实例:

#include <iostream>
#include <string>
#include "studentinfo.h"
#include "studentinfo.pb.h" int main(int argc, char* argv[])
{
student::Student s;
SetFieldAllValues(&s, "Jack", , , "");
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 ;
}

这里只是提供了设置的函数(Set函数),没有提供Get函数,不过根据类似的方式,实现Get函数应该不是很困难,这里就不给出代码了。

google的protobuf简单介绍的更多相关文章

  1. Google Protocol Buffer 简单介绍

    以下内容主要整理自官方文档. 为什么使用 Protocol Buffers .proto文件 Protocol Buffers 语法 编译.proto文件 Protocol Buffers API 枚 ...

  2. Protobuf的简单介绍、使用和分析

      Protobuf的简单介绍.使用和分析   一.protobuf是什么? protobuf(Google Protocol Buffers)是Google提供一个具有高效的协议数据交换格式工具库( ...

  3. iOS开发拓展篇-XMPP简单介绍

    iOS开发拓展篇-XMPP简单介绍 一.即时通讯简单介绍 1.简单说明 即时通讯技术(IM)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双 ...

  4. WebSocket简单介绍

    Java后端WebSocket的Tomcat实现 一.WebSocket简单介绍 随着互联网的发展,传统的HTTP协议已经很难满足Web应用日益复杂的需求了.近年来,随着HTML5的诞生,WebSoc ...

  5. TensorFlow简单介绍和在centos上的安装

    ##tensorflow简单介绍: TensorFlow™ is an open source software library for numerical computation using dat ...

  6. SQLite数据库和JPA简单介绍

    SQLite数据库和JPA简单介绍 一.SQLite简单使用 SQLite是遵循ACID的关系数据库管理系统,它的处理速度很快,它的设计目标是嵌入式的,只需要几百K的内存就可以了. 1.下载SQLit ...

  7. Epplus 使用的简单介绍

    操作Excel的主要有以下类库: MyXls(http://sourceforge.net/projects/myxls/) Koogra(http://sourceforge.net/project ...

  8. iOS开发——网络编程OC篇&(一)XMPP简单介绍与准备

    XMPP简单介绍与准备 一.即时通讯简单介绍 1.简单说明 即时通讯技术(IM)支持用户在线实时交谈.如果要发送一条信息,用户需要打开一个小窗口,以便让用户及其朋友在其中输入信息并让交谈双方都看到交谈 ...

  9. com.google.common.eventbus.EventBus介绍

    以下内容直接翻译了EventBus的注释: com.google.common.eventbus.EventBus介绍: 首先这个类是线程安全的, 分发事件到监听器,并提供相应的方式让监听器注册它们自 ...

随机推荐

  1. vue轮播,vue-awesome-swiper动态数据渲染,loop无效,轮循无效

    解决办法:在渲染数组数据前.判断是否为空 v-if="slideList.length>1" <template> <div class="ban ...

  2. js如何在浏览器添加cookie(添加、获取、删除)

    首先,简单用js将cookie保存到浏览器中,具体可按F12在这里查看(火狐浏览器) 1.js脚本方法 1)添加cookie方法 //添加cookie var addCookie = function ...

  3. jsp页面错误

    错误提示:The superclass javax.servlet.http.HttpServlet was not found on the Java Build Path. 解决办法:在build ...

  4. sqlalchemy 获取表结构。

    from sqlalchemy.engine import reflection insp = reflection.Inspector.from_engine(engine) colums=insp ...

  5. FS:[0] 链条

    0x01  用户态 在x86系统中,当线程在用户态执行时,段寄存器fs总是指向当前线程的TEB. 在Ntdll中有一个未公开的函数NtCurrentTeb() ,用来取得当前线程的TEB地址.FS:[ ...

  6. noj装载问题

    描述 有两艘船,载重量分别是c1. c2,n个集装箱,重量是wi (i=1…n),且所有集装箱的总重量不超过c1+c2.确定是否有可能将所有集装箱全部装入两艘船.   输入 多个测例,每个测例的输入占 ...

  7. method&interface

    method Go中虽没有class,但依旧有method 通过显示说明receiver来实现与某个类型组合 只能为同一个包的类型定义方法 Receiver可以是类型的值或指针 不存在方法重载 可以使 ...

  8. 关于itext生成pdf的新的demo(包含简单的提取txt文件的内容 和xml内容转化为pdf)

    一.用的iText版本为7.0.2版本,maven的配置如下: <dependencies> <!-- always needed --> <dependency> ...

  9. laravel 创建自动化生成数据库

    1.   生成 迁移脚本 php artisan make:migration create_users_table --create=users(表名) 当你⽣成⼀个模型时想要顺便⽣成⼀个 数据库迁 ...

  10. 王者荣耀交流协会 -- 第5次Scrum会议

    Scrum master : 任思佳 要求1 : 工作照片 照片由王超同学拍摄 ,王露芝同学(外援)没有参加本次会议. 要求2 : 时间跨度:2017年10月17日 18:00 - 18:25 共计2 ...