empty brace-init-lists发出有关缺少字段初始值设定项的警告

时间:2012-12-25 12:00:40

标签: c++ c++11

目标:能够列出初始化对象并具有默认值 使用尽可能少的样板初始化将所有POD初始化为0 / false 尽可能(C ++ 11)。

假设我有几个带有多个POD的类(想想文件格式 解析)。为了不处理未定义的值,我想要 默认构造对象的值初始化为0.例如, 提供我自己的默认c'tor memset() s this正常工作 这种情况,明确地命名所有成员。

然而,这是样板。更重要的是提供我自己的 无参数默认构造函数阻止我使用列表 成员初始化的初始化语法:

class Fails1 {
public:
  int a, b;
  Fails1() { memset(this, 0, sizeof(*this)); }
};

Fails1 this_works;
Fails1 this_fails{ 42, 54 }; // compiler error

我也可以添加initializer_list的构造函数,但是 那更是样板。我想避开所有那些样板。

所以我查看了编译器提供的默认构造函数 没有用户提供的默认构造函数与 如何初始化它们的各种方法。这是我得到的地方 完全糊涂了:

class A {
public:
  int a, b;
};

使用这个类,我可以使用空的初始化列表和那些 有价值而不必自己提供两个构造函数;那 是我想要的一部分。

// Example 1: default initialization
A a1;

第一个例子使用初始化;成员ab是 之后未定义(不是我想要的,我希望它们是 值初始化)。

// Example 2: Value-initialization, so this works, I guess:
A a2 = A();

示例2使用值初始化,之后不复制。所以这就是我想要的,但是,我也认为空的brace-init-lists会做同样的事情;请参阅以下示例:

// Example 3: list-initialization with empty brace-init-list
A a3{};

示例3是我认为可以解决的问题。列表初始化 8.5.4中描述了一个空的brace-init-list “列表的初始化”:;特别是8.5.4.3说:“如果是初始化器 list没有元素,T是带有默认构造函数的类类型, objectvalue-initialized“。但是,这会发出g ++ 4.7.2的警告 与-Wextra

missing initializer for member ‘A::a’ [-Wmissing-field-initializers]
missing initializer for member ‘A::b’ [-Wmissing-field-initializers]

但是没有clang ++ 3.1的警告,所以它也可能是g ++中的错误。

回到我原来的问题。如何对对象进行值初始化 无需提供我自己的boilerplatish默认构造函数 - 同时保留为其成员使用列表初始化的能力 无需提供我自己的initializer_list构造函数?

2 个答案:

答案 0 :(得分:7)

这样的简单结构
struct A { int a,b; };

显然是一个聚合,A a {};显然是聚合初始化,意味着值初始化(即零初始化),如您已经引用的§8.5.4/ 3所述。 (特别注意以下段落中给出的例子,这与你的情况几乎相同。)

海湾合作委员会的警告非常误导。

在搜索现有错误报告时,我找到了您自己提交的this one。我认为这是正确的做法。

由于您已经制定了相关的标准部分,并且其他各个人在评论中做出了贡献,我将把它作为社区Wiki答案。

答案 1 :(得分:4)

gcc关于缺少初始值设定项的警告比其他任何事情都更不利:如果有一个初始化列表,则从列表中填充值,剩余的字段初始化为零。因此,对于空的初始化列表,所有值都初始化为零。警告一个没有提及所有成员的非空初始化列表可能是合理的:我已经看到程序员为数组的第一个元素提供了非零初始化程序并假设初始化程序将重复执行的错误所有剩余的价值。

关于默认创建初始化同时还允许初始化列表,我将使用基本类型的初始化模板:

template <typename T>
struct init
{
    init(): value_() {}
    template <typename S> init(S&& value): value_(std::forward<S>(value)) {}
    T value_;
};

struct foo
{
    init<int>    i_;
    init<double> d_;
    std::string  s_;
};

int main()
{
    foo f0;
    foo f1 = { 1, 3.14, "foo" };
    foo f2 = { };
}

这种方法可以保证成员的初始化独立于如何使用类的对象,同时还支持使用初始化列表。 gcc仍然错误地警告缺少初始化器。