Я думаю, что вы правы, профсоюзы в C ++ недооценены.Это в значительной степени прямая копия союзов из C, что означает, что они не служат вариантами типов для C ++ .
. Для union
в C ++ нет простого способапредставляют правильный тип варианта.Рассмотрим следующий код, если он был допустимым:
union X {
int i;
std::string s;
};
X x;
x.s = "Hello";
x.i = 23;
Никакое количество конструкторов или деструкторов для X не гарантирует, что присваивание в последней строке вызовет ~string
перед сохранением 23
.Чтобы компилятор мог это сделать, объединение должно содержать какой-то индикатор того, какой тип хранится.Вот почему все должно быть POD.Я не знаю причин различий между именованными и безымянными союзами, хотя это относится и к обоим.
Возможно, объединения C ++ могли бы быть определены как объединения C, если все ихчлены являются POD, но содержат эту дополнительную информацию и вызывают правильные деструкторы в правильное время, если какой-либо член не является POD.Но это не простое изменение, которое вы предложили.
Вы можете несколько кропотливо написать тип варианта, написав класс, у которого есть значение, чтобы указать тип сохраненного в данный момент типа, а затем конструкторы, оператор присваивания копии идеструктор, который вы бы поместили в свой союз, если бы вам было позволено.
Используйте массив символов для хранения, размещения нового для конструкции / назначения и прямого вызова правильного деструктора в вашем деструкторе.
Остерегайтесь проблемы с выравниванием - вам необходимо убедиться, что ваше сырое хранилище правильно выровнено для любого из типов, которые вы в него помещаете.Одним из способов сделать это является его динамическое распределение.Другой способ - поместить массив char в объединение с любым встроенным типом, который имеет наибольшее требование выравнивания (если вы не знаете: все).
Единственное, что отличается в использовании, отОбъединение, которое вы хотите, состоит в том, что вместо открытых элементов данных int a
, float b
, string c
вам придется предоставлять средства доступа, которые возвращают прокси-объект (возможно, ссылку на сам объект), который способен назначатьправильно, что означает вызов деструктора для старого типа первым.Затем вы можете написать x.i() = 23
вместо x.i = 23
.
Или вы можете использовать Boost.Variant .