11

考虑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>'

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

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++ 开发人员?

4

1 回答 1

7

原因似乎是在 libc++ 的原始std::variant实现中,anunsigned 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

于 2018-12-08T20:43:40.613 回答