Почему sizeof (std :: variable & lt; char & gt;) == 8 при использовании libc ++, а не 2 (как в MSVC STL и libstdc ++)?

Рассматривать этот пример в проводнике компилятора.

По сути, у нас есть этот фрагмент кода:

#include <cstdint>
#include <variant>

enum class Enum1 : std::uint8_t { A, B };

enum class Enum2 : std::uint8_t { C, D };

using Var = std::variant< Enum1, Enum2 >;
using Var2 = std::variant< char >;

template< std::size_t s >
struct print_size;

void func() {
print_size< sizeof( Var ) >{};
print_size< sizeof( Var2 ) >{};
}

Если мы скомпилируем это с помощью GCC libstdc ++ (используя clang или GCC), мы получим ожидаемую ошибку компиляции:

error: implicit instantiation of undefined template 'print_size<2>'

Также похоже на MSVC (как и ожидалось):

error C2027: use of undefined type 'print_size<2>'

Однако при использовании clang с libc ++ я получаю эту ошибку:

error: implicit instantiation of undefined template 'print_size<8>'

Это указывает на то, что sizeof( std::variant< char > ) == 8 при использовании libc ++. Я подтвердил это в Linux (см. Ссылку на обозреватель компиляторов выше), а также в Android NDK r18 и Xcode 10 (как для iOS, так и для MacOS).

Есть ли причина для реализации libc ++ std::variant использовать столько памяти, или это просто ошибка в libc ++ и о ней следует сообщать разработчикам libc ++?

12

Решение

Кажется, причина в том, что в оригинальном libc ++ std::variant реализация unsigned int всегда используется для хранения индекса активного типа std::variantв то время как libstdc ++ выбирает наименьший целочисленный тип без знака, способный хранить самый большой индекс.

В текущем libc ++ эта оптимизация также доступна, но она не включена по умолчанию. Макрос, включающий оптимизацию (_LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION) устанавливается только если _LIBCPP_ABI_VERSION >= 2 или же _LIBCPP_ABI_UNSTABLE определено.

Я предполагаю, что, потому что оригинальная реализация не сделала эту оптимизацию, и это нарушает совместимость std::variant в обоих направлениях из-за изменения макета данных по умолчанию не было включено сохранение двоичной совместимости со старыми версиями. Более новый ABI может быть включен путем установки упомянутого макроса версии ABI, но, конечно, все библиотеки также должны быть скомпилированы с этой новой версией ABI.

Увидеть https://reviews.llvm.org/D40210

7

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]