为什么在使用 libc++ 时 sizeof( std::variant< char > ) == 8 而不是 2(就像 MSVC 的 STL 和 libstdc++)?
Why is sizeof( std::variant< char > ) == 8 when using libc++ and not 2 (like with MSVC's STL and libstdc++)?
考虑 this example on Compiler explorer。
基本上,我们有这个代码片段:
#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>'
表示使用libc++时sizeof( std::variant< char > ) == 8
。我已经在 Linux 上(参见上面的编译器资源管理器 link)以及 Android 的 NDK r18 和 Xcode 10(iOS 和苹果操作系统)。
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 版本进行编译。
考虑 this example on Compiler explorer。
基本上,我们有这个代码片段:
#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>'
表示使用libc++时sizeof( std::variant< char > ) == 8
。我已经在 Linux 上(参见上面的编译器资源管理器 link)以及 Android 的 NDK r18 和 Xcode 10(iOS 和苹果操作系统)。
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 版本进行编译。