В C++11 появился новый синтаксис инициализатора с фигурными скобками {}
auto
, был высок шанс выразить не то, что вам нужно. В C++17 появился улучшенный набор правил инициализатора. В следующем примере вы увидите, как грамотно инициализировать переменные в С++17 и какой синтаксис при этом использовать.Как это делается
Переменные инициализируются в один прием. При использовании синтаксиса инициализатора могут возникнуть две разные ситуации.
1. Применение синтаксиса инициализатора с фигурными скобками без выведения типа auto
// Три идентичных способа инициализировать переменную типа int:
int x1 = 1;
int x2 {1};
int x3 (1);
std::vector
// Вектор, содержащий три переменные типа int: 1, 2, 3
std::vector
// Такой же вектор
std::vector
// Вектор, содержащий десять переменных типа int,
// каждая из которых имеет значение 20
2. Использование синтаксиса инициализатора с фигурными скобками с выведением типа auto
auto v {1}; // v имеет тип int
auto w {1, 2}; // ошибка: при автоматическом выведении типа
// непосредственная инициализация разрешена
// только одиночными элементами! (нововведение)
auto x = {1}; // x имеет тип std::initializer_list
auto y = {1, 2}; // y имеет тип std::initializer_list
auto z = {1, 2, 3.0}; // ошибка: нельзя вывести тип элемента
Как это работает
Отдельно от механизма выведения типа auto
{}
ведет себя предсказуемо, по крайней мере при инициализации обычных типов. При инициализации контейнеров наподобие std::vector
, std::list
и т.д. инициализатор с фигурными скобками будет соответствовать конструктору std::initializer_list
этого класса-контейнера. При этом он не может соответствовать неагрегированным конструкторам (таковыми являются обычные конструкторы, в отличие от тех, что принимают список инициализаторов).std::vector
std::vector v (N, value)
. При записи std::vector v {N, value}
выбирается конструктор initializer_list
, инициализирующий вектор с двумя элементами: N
и value
. Об этом следует помнить.Есть интересное различие между оператором {}
()
. В первом случае не выполняется неявных преобразований типа: int x (1.2);
и int x = 1.2;
инициализируют переменную x
значением 1
, округлив в нижнюю сторону число с плавающей точкой и преобразовав его к типу int
. А вот выражение int x {1.2};
не скомпилируется, поскольку должно {}
()
— ближайший похожий конструктор, а также выполнится преобразование типов.Дополнительное правило, включенное в С++17, касается инициализации с выведением типа auto: несмотря на то что в C++11 тип переменной auto x{123};
std::initializer_list
с одним элементом) будет определен корректно, скорее всего, это не тот тип, который нужен. В С++17 та же переменная будет типа int
.Основные правила:
□ в конструкции auto var_name {one_element};
var_name
будет иметь тот же тип, что и one_element;□ конструкция auto var_name {element1, element2,};
□ конструкция auto var_name = {element1, element2,};
std::initializer_list
, где T
— тип всех элементов списка.В С++17 гораздо сложнее случайно определить список инициализаторов.