Я играю с [[no_unique_address]]
в c++20
.
В примере на cppreference у нас есть пустой тип Empty
и типZ
struct Empty {}; // empty class
struct Z {
char c;
[[no_unique_address]] Empty e1, e2;
};
Видимо, размер Z
должен быть хотя бы 2
потому, что типы e1
и e2
одинаковы.
Тем не менее, я действительно хочу иметь Z
с размером 1
. Это заставило меня задуматься, что насчет упаковки Empty
в некоторый класс-обертку с дополнительным параметром шаблона, который обеспечивает различные типы e1
и e2
.
template <typename T, int i>
struct Wrapper : public T{};
struct Z1 {
char c;
[[no_unique_address]] Wrapper<Empty,1> e1;
[[no_unique_address]] Wrapper<Empty,2> e2;
};
К сожалению, sizeof(Z1)==2
. Есть ли хитрость, чтобы сделать размер, Z1
чтобы быть один?
Я проверяю это с gcc version 9.2.1
иclang version 9.0.0
В моем приложении у меня есть много пустых типов формы
template <typename T, typename S>
struct Empty{
[[no_unique_address]] T t;
[[no_unique_address]] S s;
};
Который является пустым типом, если T
и S
также являются пустыми типами и отличными! Я хочу, чтобы этот тип был пустым, даже если T
и S
те же типы.
T
себе? Это будет генерировать различные типы. Прямо сейчас тот факт, что обаWrapper
унаследовали отT
вас, сдерживает вас ...T
? Прямо сейчас,T
это шаблон аргумента.T
.Ответы:
Вы не можете этого получить. Технически говоря, вы даже не можете гарантировать , что это будет пустой , даже если
T
иS
различные пустые типы. Помните:no_unique_address
это атрибут; способность его скрывать объекты полностью зависит от реализации. С точки зрения стандартов, вы не можете установить размер пустых объектов.По мере развития реализаций C ++ 20 вы должны предположить, что в
[[no_unique_address]]
целом они будут следовать правилам оптимизации пустой базы. А именно, если два объекта одного типа не являются подобъектами, вы, вероятно, можете ожидать скрытия. Но на данный момент это своего рода неудача.Что касается конкретного случая
T
иS
того же типа, это просто невозможно. Несмотря на значение имени «no_unique_address», реальность такова, что C ++ требует, чтобы с учетом двух указателей на объекты одного типа эти указатели либо указывали на один и тот же объект, либо имели разные адреса. Я называю это «правилом уникальной идентичности», иno_unique_address
это не влияет на это. Из [intro.object] / 9 :Члены пустых типов, объявленные как,
[[no_unique_address]]
имеют нулевой размер, но наличие одного и того же типа делает это невозможным.Действительно, если подумать об этом, попытка скрыть пустой тип с помощью вложения все еще нарушает правило уникальной идентификации. Рассмотрим ваши
Wrapper
иZ1
случай. Учитывая,z1
что является экземпляромZ1
, ясно, чтоz1.e1
иz1.e2
это разные объекты с разными типами. Однако,z1.e1
не не вложенz1.e2
ни внутри, ни наоборот. И в то время как они имеют разные типы,(Empty&)z1.e1
и(Empty&)z1.e2
это не разные типы. Но они указывают на разные объекты.И по уникальному правилу идентификации они должны иметь разные адреса. Так что , хотя
e1
иe2
номинально различных типов, их внутренние также должны подчиняться уникальный идентификатор против других подобъектов в том же содержащей объект. Рекурсивный.То, что вы хотите, просто невозможно в C ++ в его нынешнем виде, независимо от того, как вы пытаетесь.
источник
Насколько я могу судить, это невозможно, если вы хотите иметь обоих участников. Но вы можете специализироваться и иметь только один из членов, когда тип такой же и пустой:
Конечно, остальная часть программы, которая использует участников, должна быть изменена, чтобы иметь дело со случаем, когда есть только один участник. Не имеет значения, какой элемент используется в этом случае - в конце концов, это объект без состояния без уникального адреса. Показанные функции-члены должны сделать это простым.
Вы можете ввести больше специализаций для поддержки рекурсивного сжатия пустых пар:
Еще больше, чтобы сжать что-то вроде
Empty<Empty<A, char>, A>
.источник
sizeof(Empty<Empty<A,A>,A>{})==2
гдеA
полностью пустая структура.get_empty<T>
функцию. Затем вы можете повторно использоватьget_empty<T>
слева или справа, если он уже работает там.