2010-07-21 96 views
4

不确定是否有这样的术语,“选择”似乎工作。我正在使用C++,并且我需要创建一组工会,其中工会代表工会成员之一的选择。目前的“选择”被跟踪并始终可用。我目前手动编写这些“工会”,但我想知道是否有任何干净的伎俩自动做这种事情(半)。C++“选择”联盟

我遇到了没有赋值运算符重载或非trival构造函数或复制构造函数在我尝试实现这一点的第一回合的联合限制,但意识到,因为我实际上跟踪当前的“选择”,那里几乎在所有情况下都是非常明确的行为。

下面是我现在正在做的事情(只有两种选择,可能会达到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(); 
    } 
}; 

感谢您的帮助,所以

+0

这就是所谓的Pascal变体记录。 C/C++对于它们可能没有特别的语法,可能易于实现,并且由于工会提供了一种实现类似结果的方法,所以为什么要麻烦。 – ninjalj 2010-07-21 21:37:41

+0

感谢信息+历史:) – LorenVS 2010-07-21 21:45:31

回答

14
任何评论......

尝试查看boost :: any和boost :: variant。 第一个允许你在boost :: any变量中插入任何类型,并跟踪它的类型。 它更像是一个“运行时检查”类型。 第二个强制你定义所有要插入的类型(即boost :: variant < Choice1,Choice2,...>),但在编译时强制执行更多的类型检查。

两者都用于存储不同类型的对象,例如具有不同类型的容器(std :: vector可以处理std :: string或int)。

+0

提升:变体似乎很接近,有没有什么办法可以区分两种不同的具有相同类型的选择?假设choice2和choice3都是整数,但代表不同的东西,任何方式来处理与变体? – LorenVS 2010-07-21 21:40:12

+2

您可以为此定义您自己的通用模板类型包装器,例如:'template struct distinct_type {Value value; }'。然后,您可以根据需要创建不同的包装:'distinct_type <0, int>','distinct_type <1, int>'等等。更好的是,定义一个'enum'并将其常量用于'Discriminant'。 – 2010-07-21 21:53:07

6

更一般地说,这是一个“歧视联盟”或tagged union。正如所提到的boost :: variant或boost :: any都是这种策略的实现。

+0

谢谢你的名字......不太清楚该怎么称呼它 – LorenVS 2010-07-21 21:40:31

3

即使你和我一样,一般都喜欢变种来继承(我是一种ML类型的人),但继承是C++的方式。

而不是使用boost::variant<Apple, Pear, Banana>的对象,使用智能指针指向Fruit的对象。继承具有开放的优势 - 您可以随时添加更多类型的Fruit。虚拟方法通常比开关或语句清晰得多。给继承一个机会;你会学会喜欢它。