protobuf oneof
功能很棒。但是,仅当oneof
中的字段是原始类型或protobuf消息时才可以使用它。如果我有两个类A
和B
,它们是由C ++代码而不是protobuf消息定义的,并且我想实现一个AorB
类,例如:
message AorB {
oneof oneof_name {
A a = 1;
B b = 2;
}
}
我试图读取oneof
字段的生成的C ++代码,以了解其实现方式。但这很复杂。有没有简洁的方法来实现这一目标?还是我可以直接使用的任何模板?
答案 0 :(得分:1)
取决于您可以使用哪个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