目标:能够列表初始化对象,并使用尽可能少的样板(C++11)将所有PODs初始化为0/false。
假设我有几个类和几个PODs (想想文件格式解析)。为了不处理未定义的值,我希望将默认构造的对象的值初始化为0。例如,提供我自己的默认c‘’tor,即memset()的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;第一个示例使用初始化;成员a和b后来没有定义(不是我想要的,我希望它们是值初始化的)。
// Example 2: Value-initialization, so this works, I guess:
A a2 = A();示例2使用值初始化,之后不会复制。这就是我想要的,然而,我也认为空的example init-list也会做同样的事情;请参见下面的示例:
// Example 3: list-initialization with empty brace-init-list
A a3{};示例3是我认为可以解决问题的方法。在8.5.4“List - initialization”中描述了带有空brace-init-list的列表初始化:;特别是8.5.4.3说:“如果初始化器list没有元素,并且T是具有默认构造函数的类类型,则objectvalue-initialized”。但是,对于带有-Wextra的g++ 4.7.2,这会发出警告
missing initializer for member ‘A::a’ [-Wmissing-field-initializers]
missing initializer for member ‘A::b’ [-Wmissing-field-initializers]不过,clang++ 3.1没有发出警告,所以它也可能是g++中的错误。
所以回到我最初的问题。如何在不提供自己的initializer_list默认构造函数的情况下对对象进行值初始化,同时保留对其成员使用列表初始化的能力,而不必提供自己的boilerplatish构造函数?
发布于 2012-12-25 22:37:06
一个普通的结构,比如
struct A { int a,b; };显然是一个聚合,而A a {};显然是聚合初始化,意味着值初始化(即零初始化),正如您已经引用的§8.5.4/3所描述的那样。(请特别注意下一段中给出的示例,它实际上与您的情况完全相同。)
GCC的警告极具误导性。
在搜索现有的bug报告时,我找到了this one,这是您自己提交的。我认为这是正确的做法。
由于您已经制定了相关的标准部分,并且其他人也在评论中做出了贡献,因此我将把这篇文章作为社区Wiki的回答。
发布于 2012-12-25 22:49:35
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仍然错误地警告说,缺少初始化器。
https://stackoverflow.com/questions/14030467
复制相似问题