Объединение “выбора” C++

Не уверенный, если существует термин для этого, "выбор", кажется, работает. Я работаю в 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();
    }
};

Спасибо за Вашу справку ТАК

6
задан timrau 8 October 2012 в 15:37
поделиться

3 ответа

Попробуйте посмотреть на boost::any и boost::variant. Первый позволяет вставлять любой тип в переменную boost::any, отслеживая ее тип. Это скорее тип "check-at-runtime". Вторая заставляет вас определить все типы, которые будут вставлены (т.е. boost::variant < Choice1, Choice2, ... > ), но обеспечивает более тщательную проверку типов во время компиляции.

Оба используются для хранения объектов разных типов, например, для разнородных контейнментов (std::vector может работать с std::string или int, например).

15
ответ дан 8 December 2019 в 03:38
поделиться

В более общем случае это "дискриминированное объединение" или маркированное объединение. Как уже упоминалось, boost::variant или boost::any являются обеими реализациями этой стратегии.

6
ответ дан 8 December 2019 в 03:38
поделиться

Даже если вы похожи на меня и обычно предпочитаете варианты наследованию (я парень из ML), наследование - это способ сделать это в C ++.

Вместо использования объекта boost :: variant используйте умный указатель на объект Fruit . Преимущество наследования в том, что оно открыто - вы всегда можете добавить больше типов Fruit . Виртуальные методы обычно намного чище, чем переключатели или операторы if. Дайте шанс наследству; вы научитесь любить это.

3
ответ дан 8 December 2019 в 03:38
поделиться
Другие вопросы по тегам:

Похожие вопросы: