使用C++11的成员初始值设定项列表中的初始值设定值列表语法



我一直在学习"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)
{}

那么,区别是什么?什么时候应该优先选择其中一个?

那么有什么区别呢?

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

歪歪扭扭的大括号适用于这些,也适用于聚合——简单的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,请使用圆括号;或者强制使用特定的构造函数。

当你需要一种不受支持的初始化形式时,最好使用大括号;或者当你只是想让初始化"做正确的事情"时。

在两者都做相同事情的情况下,选择在很大程度上是审美的。

在一些真正令人讨厌的边缘情况下,可能存在差异:

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]

无论vu只是函数中的变量还是初始化列表中初始化的类的成员,这都是正确的。

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

简短的描述是:成员初始值设定项列表中的符号与其他地方初始化的变量的符号相匹配。遗憾的是,描述它的作用一点也不容易,因为在构造函数调用中使用花括号有两个有点冲突的变化:

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

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

最新更新