std::array
必须明确定义,因此即使不允许 std::array<T, 0>
,int[0]
也是明确定义的(尽管 GCC 为其实现了扩展)。
但是,在 GCC、Clang 和 MSVC 上,
std::array<T, 0>
不会被视为零大小的结构,即它的行为不像具有尾随填充,因此 [[no_unique_address]]
和空基优化不会与它一起工作。例如:
#include <array>
struct Tester {
[[no_unique_address]] std::array<char, 0> arr;
char c;
};
struct Tester2 : std::array<char, 0> {
char c;
};
// true on GCC, Clang, and MSVC at least:
static_assert(sizeof(Tester) == 2);
static_assert(sizeof(Tester2) == 2);
这令人惊讶,因为它显然可以作为空结构实现。这是标准规定的吗?
注意:我研究了 libstdc++ 的代码,它的工作原理是这样的,因为
std::array<char, 0>
包含一个不是 [[no_unique_address]]
的空结构实例,并且没有使用空基类优化,即它看起来像这样:
template <typename T>
struct array<T, 0> {
struct {} empty; // no [[no_unique_address]]!
};
但这并不能解释为什么是这样设计的。尽管
[[no_unique_address]]
直到 C++20 才出现,但空基类优化在标准库的其他部分中被广泛使用,因此如果需要的话,这绝对是可以完成的事情。
编辑:我的问题被标记为 C++ 编译器实际上符合零大小数组 SFINAE 规则吗? 的重复。这根本不是真的。我的问题是关于库功能
std::array
,即使大小为 0,该功能也由标准明确定义。链接的问题是关于数组的语言功能。
空的
struct
会不会与C++11中的双括号初始化“问题”有关?
std::array<T,N> myArray = {{ ... }};
在 N3526 之前,存在需要将大括号加倍才能列表初始化
std::array
的情况。如果 std::array<T,0>
已实现为简单的空 struct
,则无法编译通过双括号进行的初始化。
所以也许为了确保所有
std::array
实例化都可以使用相同的语法进行初始化,他们添加了一个空的内部类?