Я прошел черезТур по С ++‘и Бьярне использует функцию списка инициализатора 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]
Это верно независимо от того, v
а также u
являются просто переменными в функции или являются членами класса, инициализированного в списке инициализации.
Но за исключением случаев, когда std::initializer_list<T>
конструктор перекрывается с обычным конструктором, принимающим такое же количество аргументов, различий нет.
Краткое описание: обозначение в списке инициализатора члена совпадает с обозначением переменных, инициализированных в другом месте. К сожалению, описание того, что он делает, не так просто, потому что есть два несколько противоречивых изменения, связанных с использованием фигурных скобок для вызовов конструктора:
std::initializer_list<T>
без дополнительной пары скобок / фигурных скобок. Если есть конструктор, принимающий std::initializer_list<T>
(для подходящего типа T
) этот конструктор используется при использовании фигурных скобок.Поставить по другому, если есть нет std::initializer_list<T>
конструктор, но какой-то другой определяемый пользователем конструктор использование скобок и фигурных скобок эквивалентно. В противном случае это вызывает std::initializer_list<T>
конструктор. … и я предполагаю, что мне не хватает нескольких деталей, поскольку вся инициализация на самом деле довольно сложна.