Использование #pragma pack
вызывает поведение, определяемое реализацией.
Кроме того, foo
не является классом стандартного макета из-за наличия нескольких подобъектов базового класса одного типа так что даже без pack
его компоновка не подлежит никакому ABI.
Полагаться на компоновку класса нестандартной компоновки - это, честно говоря, ужасная идея, и, безусловно, есть лучший способ достичь любой цели здесь.
Вот несколько возможных подходов, которые не связаны с изменением кода (конечно, даже если какой-то из них пока работает, он может измениться в любое время):
- Используйте clang или g ++ вместо MSV C в Windows.
- Попробуйте передать флаги в MSV C, чтобы изменить поведение EBCO см. Здесь для записи , может быть, это может быть сделано, чтобы дать версию 0 1 5.
- Отредактируйте исходный код g cc или clang, чтобы создать свой собственный компилятор и дать желаемую раскладку.
In g cc оптимизация пустого базового класса отключена классом, имеющим две базы одного и того же типа, поэтому вы можете включить его с изменением кода , как предлагается в комментариях к этому вопросу :
struct empty_struct {};
struct E2 {};
class derived_struct : public E2
(а остальная часть кода такая же, как в вашем примере). Это дает мне вывод 0 0 4
даже без прагмы. Мне не известны какие-либо флаги для g cc или clang, которые могли бы изменить поведение EBCO.
Основанием для этого правила является то, что в стандарте C ++, если два допустимых указателя одного типа имеют одинаковое значение тогда они должны указывать на один и тот же объект. Два пустых подобъекта являются разными объектами, поэтому для них должны существовать уникальные адреса. MSV C не соответствует этому.
В C ++ 20 есть атрибут [[no_unique_address]]
, который предположительно ослабляет это требование, однако я попробовал его в своей установке g ++ 9.2.0 и это не изменило макет. Не уверен, является ли это ошибкой или предполагаемым поведением, но в любом случае это не кажется решением проблемы.