[英]C++ implementation of protobuf `oneof` feature for non-protobuf class
The protobuf oneof
feature is great. protobuf
oneof
功能很棒。 But it only can be used when the fields in oneof
are either a primitive type or a protobuf message. 但它只能当在领域中使用
oneof
是原始类型或protobuf的消息。 What if I have two classes A
and B
, which are defined by C++ code instead of protobuf messages, and I want to implement a class AorB
which is like: 如果我有两个类
A
和B
,它们是由C ++代码而不是protobuf消息定义的,并且我想实现一个类AorB
,例如:
message AorB {
oneof oneof_name {
A a = 1;
B b = 2;
}
}
I tried to read the generated C++ code of a oneof
field to see how that is implemented. 我尝试阅读
oneof
字段的生成的C ++代码,以了解如何实现。 But it's pretty complicated. 但这很复杂。 Is there any concise way to implement this?
有没有简洁的方法来实现这一目标? Or any template which I can use directly?
还是我可以直接使用的任何模板?
Depending on which version of C++ you're able to use, your options are std::variant
, roll your own with variadic templates, or roll your own with union
. 根据您可以使用的C ++版本,您的选择为
std::variant
,使用可变参数模板滚动自己或使用union
滚动自己。 std::variant
was added to the language in C++17 and will definitely be the easiest to manage. std::variant
已添加到C ++ 17语言中,并且肯定是最容易管理的。 The variadic template version is tricky. 可变参数模板版本比较棘手。
union
works to the beginning of the language and would look something like. 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;
}
}
};
at a baseline that kinda maybe works. 在某种程度上可能起作用。 There's a pile of details to get it right, though.
不过,还有很多细节可以解决。 The basics of it are that a union puts the values in overlapping memory, only one is valid at a time, and it's undefined behavior to access the wrong one.
它的基本原理是,联合将值放入重叠的内存中,一次仅一个有效,并且访问错误的值是不确定的行为。 You also need to manually destruct before re-assigning the held value.
重新分配保留值之前,您还需要手动销毁。
I probably missed a detail somewhere in there. 我可能错过了某个地方的细节。 I'd rather leave it to
std::variant
but if you need to write your own discriminated union, it would start something like the code above. 我宁愿将其留给
std::variant
但是如果您需要编写自己的有区别的联合,它将开始类似于上面的代码。
More details on variant here: https://en.cppreference.com/w/cpp/utility/variant 有关变体的更多详细信息,请访问: https : //en.cppreference.com/w/cpp/utility/variant
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.