不确定是否有这个术语,“选择”似乎有效。我在C ++工作,我需要创建一些联合,其中union表示联盟成员之一的选择。跟踪当前的“选择”并始终可用。我目前正在手动编写这些“联合”代码,但我想知道是否有任何巧妙的技巧可以自动执行此类(半)。
我遇到了没有赋值运算符重载或非trival构造函数或复制构造函数的union限制,这是我第一次试图实现这一点,但意识到因为我实际上正在跟踪当前的“选择”,所以在几乎所有情况下都要采取非常明确的行为。
这就是我现在正在做的事情(只有两个选择,最多可以是10或15),并且它的代码数量非常大,几乎所有代码都只是样板。另外,如果有人对我下面的内容是否有效甚至是有效的评论有任何意见,那么仍然会发现一些C ++的疯狂......
struct MyChoice
{
struct Choice1
{
int a;
char* b;
};
struct Choice2
{
bool c;
double d;
};
enum Choice
{
Choice_Choice1,
Choice_Choice2
} choice;
char _value[max(sizeof(Choice1),sizeof(Choice2))]; // could be private
Choice1& choice1()
{
if(choice == Choice_Choice2)
{
(*(Choice2*)_value)->~Choice2();
(*(Choice1*)_value) = Choice1();
choice = Choice_Choice1;
}
return *(Choice1*)_value;
}
Choice2& choice2()
{
if(choice == Choice_Choice1)
{
(*(Choice1*)_value)->~Choice1();
(*(Choice2*)_value) = Choice2();
choice = Choice_Choice2;
}
return *(Choice2*)_value;
}
MyChoice()
{
_choice = Choice_Choice1;
(*(Choice1)_value) = Choice1();
}
MyChoice(const MyChoice& other)
{
this->_choice = other.choice;
if(this->_choice == Choice_Choice1)
(*(Choice1*)_value) = other.choice1();
else
(*(Choice2*)_value) = other.choice2();
}
~MyChoice()
{
if(_choice == Choice_Choice1)
(*(Choice1)_value)->~Choice1();
else
(*(Choice2)_value)->~Choice2();
}
};
感谢您的帮助SO
答案 0 :(得分:15)
尝试查看boost :: any和boost :: variant。 第一个允许您在boost :: any变量中插入任何类型,跟踪其类型。 它更像是“运行时检查”类型。 第二个强制您定义要插入的所有类型(即boost :: variant< Choice1,Choice2,...>),但在编译时强制执行更多类型检查。
两者都用于存储不同类型的对象,例如具有异构容器(std :: vector可以处理std :: string或int)。
答案 1 :(得分:6)
更一般地说,这是一个'受歧视的联盟'或tagged union。如前所述,boost :: variant或boost :: any都是这种策略的实现。
答案 2 :(得分:4)
在C ++ 17中,标准库中直接提供了一种std::variant
类型。
以下是cppreference中示例源代码的一小部分摘录:
#include <variant>
#include <string>
#include <cassert>
using namespace std::literals;
int main()
{
std::variant<int, float> v, w;
v = 12; // v contains int
int i = std::get<int>(v);
w = std::get<int>(v);
w = std::get<0>(v); // same effect as the previous line
w = v; // same effect as the previous line
// std::get<double>(v); // error: no double in [int, float]
// std::get<3>(v); // error: valid index values are 0 and 1
}
答案 3 :(得分:3)
即使你像我一样,并且通常更喜欢变体继承(我是ML类型的人),继承是C ++的方法。
使用指向boost::variant<Apple, Pear, Banana>
对象的智能指针,而不是使用Fruit
的对象。继承具有开放的优势 - 您可以随时添加更多类型的Fruit
。虚拟方法通常比switch或if语句更清晰。给继承一个机会;你会学会喜欢它。