在隐式构造函数中不检查C ++ 11初始化列表长度

时间:2016-05-08 10:44:11

标签: c++ c++11 constructor initializer-list

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

struct LayerData
{
    uint32_t d[60];
};

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

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

它编译正确。

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

3 个答案:

答案 0 :(得分:3)

N3337 8.5.1 / 7

  

如果列表中的初始化子条款少于聚合中的成员,那么每个成员   未明确初始化应从空初始化列表(8.5.4)初始化。

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

使用1,ss.b使用“asdf”初始化ss.a,使用 int()形式的表达式的值初始化ss.c,   也就是说,0

因此,在您的示例中,首先使用rand()其他int() 0初始化前5个元素,即SELECT * FROM Course JOIN Subject ON Course.id = Subject.course_id WHERE /* Your filters here */

答案 1 :(得分:2)

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

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

可以使用比其包含的项更少的项来初始化数组。在这种情况下,剩余的元素是初始值(即零)。

答案 2 :(得分: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."
}
匆匆写了,但你应该明白这个想法。