为什么sizeof(std :: variant <char>)== 8使用libc ++而不是2(比如MSVC的STL和libstdc ++)?

DoD*_*oDo 12 c++ libc++ c++17 std-variant

在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 ) >{};
}
Run Code Online (Sandbox Code Playgroud)

如果我们使用GCC的libstdc ++(使用clang或GCC)编译它,我们会得到预期的编译错误:

error: implicit instantiation of undefined template 'print_size<2>'
Run Code Online (Sandbox Code Playgroud)

此外,与MSVC类似(如预期):

error C2027: use of undefined type 'print_size<2>'
Run Code Online (Sandbox Code Playgroud)

但是,当使用clang与libc ++时,我收到此错误:

error: implicit instantiation of undefined template 'print_size<8>'
Run Code Online (Sandbox Code Playgroud)

这表明sizeof( std::variant< char > ) == 8使用libc ++时.我已经确认在Linux上(参见上面的编译器浏览器链接),还有Android的NDK r18和Xcode 10(iOS和MacOS).

有没有理由让libc ++实现std::variant使用如此多的内存,或者这只是libc ++中的一个错误,应该向libc ++开发人员报告?

use*_*163 7

原因似乎是在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