4

我一直在经历“ A Tour of C++ ”,Bjarne 在构造函数的成员初始化中使用了 c++11 初始化器列表功能,就像这样(使用大括号):

A a;
B b;
Foo(Bar bar):
  a{bar.a}, b{bar.b}
{}

但是,这不会在 c++11 之前编译。与旧的成员初始化器列表有什么区别(使用圆括号):

Foo(Bar bar):
  a(bar.a), b(bar.b)
{}

那么有什么区别,什么时候应该优先于另一个呢?

4

3 回答 3

9

那么区别是什么呢?

圆括号仅适用于非类类型,或具有适合括号中参数数量的构造函数的类型。

波浪花括号适用于这些,也适用于聚合 -struct没有构造函数的简单或数组类型。所以以下将起作用:

struct {
    int a,b;
} aggregate;
int array[2];

Foo() : aggregate{1,2}, array{3,4} {}

最后,大括号将匹配采用适当类型initializer_list的构造函数,而不是带有参数的构造函数来匹配参数。例如:

std::vector<int> v1;
std::vector<int> v2;

Foo() :
    v1(10,2),   // 10 elements with value 2
    v2{10,2}    // 2 elements with value 10,2
{}

什么时候应该优先于另一个?

如果您想更清楚地表明初始化使用的是构造函数而不是聚合或,则首选圆括号initializer_list;或强制使用特定的构造函数。

当您需要一种不支持的初始化形式时,首选大括号;或者当您只希望初始化“做正确的事情”时。

在两者都做同样事情的情况下,选择主要是审美。

于 2014-11-07T15:44:47.703 回答
3

一些非常烦人的边缘情况可能会有所不同:

std::vector<int> v{3, 2}; // constructs a vector containing [3, 2]
std::vector<int> u(3, 2); // constructs a vector containing [2, 2, 2]

无论v和是否u只是函数中的变量或者是在初始化列表中初始化的类的成员,这都是正确的。

但是除了构造函数与采用相同数量参数的普通构造函数重叠的情况之外std::initializer_list<T>,没有区别。

于 2014-11-07T15:44:29.747 回答
1

简短的描述是:成员初始化列表中的符号与在别处初始化的变量的符号相匹配。遗憾的是,描述它的作用并不容易,因为在构造函数调用中使用花括号有两个有些冲突的变化:

  1. 统一的初始化语法旨在使所有构造都使用花括号,并且它只会调用相应的构造函数,即使它是默认参数或类型根本没有构造函数并且使用直接初始化。
  2. 为了支持可变数量的参数,可以使用花括号来提供std::initializer_list<T>没有额外的一对括号/花括号。如果有一个构造函数采用std::initializer_list<T>(对于合适的类型T),则在使用花括号时使用此构造函数。

换句话说,如果没有 std::initializer_list<T>构造函数但有一些其他用户定义的构造函数,则括号和花括号的使用是等效的。否则它调用std::initializer_list<T>构造函数。...我想,我错过了一些细节,因为整个初始化实际上非常复杂。

于 2014-11-07T15:41:21.003 回答