Не уверенный, если существует термин для этого, "выбор", кажется, работает. Я работаю в C++, и у меня есть набор объединений, которые я должен создать, где объединение представляет выбор одного из членов объединения. Текущий "выбор" прослежен и всегда доступен. Я в настоящее время кодирую эти "объединения" вручную, но я задаюсь вопросом, существует ли какой-либо аккуратный прием для того, чтобы сделать этот вид вещи (полу-) автоматически.
Я столкнулся с ограничением объединения не наличия перегрузок оператора присваивания или non-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();
}
};
Спасибо за Вашу справку ТАК
Попробуйте посмотреть на boost::any и boost::variant. Первый позволяет вставлять любой тип в переменную boost::any, отслеживая ее тип. Это скорее тип "check-at-runtime". Вторая заставляет вас определить все типы, которые будут вставлены (т.е. boost::variant < Choice1, Choice2, ... > ), но обеспечивает более тщательную проверку типов во время компиляции.
Оба используются для хранения объектов разных типов, например, для разнородных контейнментов (std::vector может работать с std::string или int, например).
В более общем случае это "дискриминированное объединение" или маркированное объединение. Как уже упоминалось, boost::variant или boost::any являются обеими реализациями этой стратегии.
Даже если вы похожи на меня и обычно предпочитаете варианты наследованию (я парень из ML), наследование - это способ сделать это в C ++.
Вместо использования объекта boost :: variant
используйте умный указатель на объект Fruit
. Преимущество наследования в том, что оно открыто - вы всегда можете добавить больше типов Fruit
. Виртуальные методы обычно намного чище, чем переключатели или операторы if. Дайте шанс наследству; вы научитесь любить это.