Рассматривать этот пример в проводнике компилятора.
По сути, у нас есть этот фрагмент кода:
#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 ++?
Кажется, причина в том, что в оригинальном 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
Других решений пока нет …