不确定是否有一个术语来描述这个,“选择”似乎起作用了。我在C中工作,我需要创建一堆联合体,其中联合体表示联合体成员之一的选择。当前的“选择”被跟踪,并且总是可用的。我目前正在手动编写这些“联合体”,但我想知道是否有什么巧妙的技巧可以(半)自动地完成这类事情。
在我第一次尝试实现这个的时候,我遇到了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();
}
};
谢谢你的帮助所以
4条答案
按热度按时间xdyibdwo1#
试着看看boost::any和boost::variant。第一个允许你在boost::any变量中插入任何类型,跟踪它的类型。它更像是一个“运行时检查”类型。第二个强制你定义所有要插入的类型(即boost::variant〈Choice1,Choice2,...〉),但在编译时强制更多的类型检查。
这两种类型都用于存储不同类型的对象,例如,具有异构容器(例如,std::vector可以处理std::string或int)。
zlhcx6iw2#
更一般地说,这是一个“区分联合”或tagged union。如前所述,boost::variant或boost::any都是此策略的实现。
mf98qq943#
在C++ 17中,标准库中直接提供了
std::variant
类型。下面是cppreference示例源代码的一小段摘录:
4urapxun4#
即使你像我一样,通常喜欢变体而不是继承(我是ML类型的人),继承也是C++的方式。
不要使用
boost::variant<Apple, Pear, Banana>
的对象,而是使用指向Fruit
的对象的智能指针。继承的优点是开放的--你总是可以添加更多类型的Fruit
。虚方法通常比开关或if语句干净得多。给予继承一个机会吧;你会喜欢的。