隐式构造函数中未检查 C++11 初始值设定项列表长度

C++11 initializer list length is not checked in implicit constructor

我发现当一个带有默认构造函数的简单数据结构包含一个数组时,可以使用不同数量的参数调用默认构造函数,即:

struct LayerData
{
    uint32_t d[60];
};

可以通过以下方式初始化:

LayerData in({rand(),rand(),rand(),rand(),rand()});

并且编译正确。

这是 C++11 中的预期行为吗?隐式构造函数中是否没有编译时大小检查?

有编译时检查。这不会编译:

struct A
{
  int b[3];
};

int main()
{
  A a { 1, 2 };       // no problem here. equivalent to 1, 2, 0
  A b { 1, 2, 3, 4 }; // problem here. too many initializers
}

因为:

/tmp/gcc-explorer-compiler11648-73-eh15v1/example.cpp: In function 'int main()':
10 : error: too many initializers for 'A'
A b { 1, 2, 3, 4 };
^
Compilation failed

数组初始化时所包含的项目可能少于其包含的项目。在这种情况下,剩余的元素被值初始化(即零)。

N3337 8.5.1/7

If there are fewer initializer-clauses in the list than there are members in the aggregate, then each member not explicitly initialized shall be initialized from an empty initializer list (8.5.4).

struct S { int a; const char* b; int c; };
S ss = { 1, "asdf" };

initializes ss.a with 1, ss.b with "asdf", and ss.c with the value of an expression of the form int(), that is, 0.

因此在您的示例中,前 5 个元素用 rand() 初始化,其他元素用 int() 初始化,即 0

GCC 4.8.4 可以很好地编译代码。 并非每个编译器都可以,MSVC++ 14 (VS 2015) 无法编译

LayerData in({rand(),rand(),rand(),rand(),rand()});

但它确实编译

LayerData in{{rand(),rand(),rand(),rand(),rand()}};

使用 C++ 11 通用表示法

查看 GCC 允许这样做的原因,似乎是因为它在堆栈上分配类型,然后使用 XMM 一次将 32 位(针对 x64 编译时为 64 位)移动到内存位置。也许这会随着类型的大小而变化,但通常我会说,如果您需要强制执行相同的长度,那么您无论如何都不应该像这样公开类型。请注意,通用符号实际上可以为您所用,并且使用模板,您可以形成看起来与您尝试做的非常相似的东西,并强制执行相同数量的参数:

#include <cstdint>

template <int N>
class LayerData
{
    static_assert(N > 0, "Number must be greater than 0");
public:
    uint32_t d[N];
    template<typename... Args>
    LayerData(Args&&... args) : d{uint32_t(args)...}
    {
        static_assert(sizeof...(Args) == N, "Invalid number of constructor arguments.");
    }
};

int main()
{
    LayerData<4> in1{1, 2, 3, 4}; //Fine
    LayerData<60> in2{1, 2, 3, 4}; //Causes error "Invalid number of constructor arguments."
}

仓促写的,不过你应该明白了。