c++ - 用于非 protobuf 类的 protobuf `oneof` 功能的 C++ 实现
问题描述
protobufoneof
功能很棒。但它只能在字段oneof
为原始类型或 protobuf 消息时使用。如果我有两个类A
和B
,它们由 C++ 代码而不是 protobuf 消息定义,并且我想实现一个类似的AorB
类:
message AorB {
oneof oneof_name {
A a = 1;
B b = 2;
}
}
我试图阅读生成的oneof
字段的 C++ 代码,以了解它是如何实现的。但这很复杂。有什么简洁的方法来实现这个吗?或者我可以直接使用的任何模板?
解决方案
根据您能够使用的 C++ 版本,您的选项是std::variant
、使用可变参数模板自己制作,或者使用union
. std::variant
在 C++17 中被添加到语言中,并且肯定是最容易管理的。可变参数模板版本很棘手。
union
工作到语言的开头,看起来像。
struct MyAorB {
union {
A a;
B b;
};
~MyAorB() { destruct(); }
MyAorB& operator=(const MyAorB&) = delete;
MyAorB& operator=(MyAorB&&) = delete;
MyAorB(const MyAorB&) = delete;
MyAorB(const MyAorB&&) = delete;
enum { HOLDS_NONE, HOLDS_A, HOLDS_B } which_one = HOLDS_NONE;
A& get_A() { assert(which_one == HOLDS_A); return a; }
B& get_B() { assert(which_one == HOLDS_B); return b; }
void set_A(A new_a) { which_one = HOLDS_A; destruct(); a = std::move(new_a); }
void set_B(B new_b) { which_one = HOLDS_B; destruct(); b = std::move(new_b); }
void destruct() {
switch (which_one) {
case HOLDS_A: a.~A(); break;
case HOLDS_B: b.~B(); break;
default: break;
}
}
};
在一个可能有效的基线上。不过,有很多细节可以让它正确。它的基础是联合将值放在重叠的内存中,一次只有一个有效,访问错误的值是未定义的行为。您还需要在重新分配持有的值之前手动销毁。
我可能错过了那里某个地方的细节。我宁愿把它留给它,std::variant
但如果你需要编写自己的有区别的联合,它会像上面的代码一样开始。
此处有关变体的更多详细信息:https ://en.cppreference.com/w/cpp/utility/variant
推荐阅读
- r - R - 无法正确显示二进制文件中的灰度图像
- android - 禁用 EditText 但接收触摸/单击事件
- json - Oracle JSON 函数不向小数添加前导零
- java - 无法将项目添加到 JcomboBox Java
- docker - 在与 /var/lib/docker/volume 不同的文件夹中创建 docker 卷
- angular - 如何在 Angular 4 中使用 dhtmlx 调度程序
- windows - 在 Windows 上不使用 OpenSSL 从 pfx 文件或证书存储中提取私钥
- asp.net - “运行”(绿色箭头)上的 Visual Studio 2017 下拉菜单不存在
- sql - 在 SQL / Impala 中对 SUM 的值进行逆向工程
- python - Plotly - 如何突出显示同一图中两个数字的两个结果