В зависимости от того, какую версию C ++ вы можете использовать, вы можете выбрать std::variant
, выбрать свой собственный вариант с помощью шаблонов с переменным числом аргументов или свой собственный с помощью union
. std::variant
был добавлен к языку в C ++ 17 и определенно будет самым простым в управлении. Вариативная версия шаблона хитрая.
union
работает до начала языка и будет выглядеть примерно так.
struct MyAorB {
union {
A a;
B b;
};
~MyAorB() { destruct(); }
MyAorB& operator=(const MyAorB&) = delete;
MyAorB& operator=(MyAorB&&) = delete;
MyAorB(const MyAorB&) = delete;
MyAorB(const MyAorB&&) = delete;
enum { HOLDS_NONE, HOLDS_A, HOLDS_B } which_one = HOLDS_NONE;
A& get_A() { assert(which_one == HOLDS_A); return a; }
B& get_B() { assert(which_one == HOLDS_B); return b; }
void set_A(A new_a) { which_one = HOLDS_A; destruct(); a = std::move(new_a); }
void set_B(B new_b) { which_one = HOLDS_B; destruct(); b = std::move(new_b); }
void destruct() {
switch (which_one) {
case HOLDS_A: a.~A(); break;
case HOLDS_B: b.~B(); break;
default: break;
}
}
};
на базовом уровне, который вроде может работать. Хотя есть куча деталей, чтобы понять это правильно. Основой этого является то, что объединение помещает значения в перекрывающуюся память, только одно допустимо за один раз, и это неопределенное поведение для доступа к неправильному. Вам также необходимо вручную уничтожить перед повторным присвоением удерживаемого значения.
Я, вероятно, пропустил детали где-то там. Я бы предпочел оставить это на std::variant
, но если вам нужно написать свой собственный дискриминируемый союз, он запустит что-то вроде кода выше.
Подробнее о варианте здесь: https://en.cppreference.com/w/cpp/utility/variant