C ++ "Choice"

Not sure if there is a term for this, it seems that "choice" works. I work in C ++, and I have many unions that I need to create, where the union is the choice of one of the union members. The current "selection" is tracked and always available. I am currently coding these “unions” manually, but I wonder if there is any neat trick to do this kind of (semi) automatically.

I came across a union limitation of the absence of operator overloads or constructor constructors or copy constructors in my first attempt to try to implement this, but realized that since I actually track the current “choice”, there is a very specific behavior that is required in almost every situation .

Here is what I am doing right now (only for two options it can be up to 10 or 15), and this is quite significant code, almost all of which is just a template. Also, if anyone has comments about whether what I really have, really, that would be awesome, still raising some C ++ craziness ...

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(); } }; 

Thanks for your help SO

+4
source share
3 answers

Try looking at boost :: any and boost :: variant. The first allows you to embed any type in boost :: any variable, tracking its type. It is rather a check-at-runtime type. The second of them forces you to determine all the types that you need to insert (for example, boost :: variant <Choice1, Choice2, ...>), but resort to additional type checking at compile time.

Both are used to store objects of different types, for example, for heterogeneous content (std :: vector can handle std :: string or int, for example).

+14
source

More generally, it is a “discriminatory union” or tagged union . As mentioned boost :: variant or boost :: any are both options for implementing this strategy.

+6
source

Even if you are like me and usually prefer inheritance options (I'm a guy like ML), inheritance is a C ++ way.

Instead of using the boost::variant<Apple, Pear, Banana> object, use a smart pointer to the Fruit object. The advantage of Inheritance is that you are open - you can always add more types of Fruit . Virtual methods are usually much cleaner than switches or if statements. Give inheritance a chance; you learn to love it.

+3
source

Source: https://habr.com/ru/post/1316476/


All Articles