Инициализация 2/2.
Непонятно что делать с этой инфой. Давайте посмотрим на пару примеров, которые помогут сделать выводы. Самый простой:
int m();Вот я хочу инициализировать переменную
m по месту. Но, учитывая most vexing parse, это у вас не переменная, а объявление функции. Всё сломалось. Или гораздо более стрёмный кейс:vector<int> v(istream_iterator<int>(cin), istream_iterator<int>());Fuck. Это тоже объявление функции (оно скомпилируется и вы получите ошибку в совсем другом месте!). Оставим разбор этого выражения читателю.
Из забавного (если конечно больно можно считать за смешно) следующие кейсы:
int i(1, 2);
int i = (1, 2);
int i = int(1, 2);
auto i(1, 2);
auto i = (1, 2);
auto i = int(7, 9);Будет ли первое компилироваться? Конечно же нет. Наверное тогда и второе? Ошибка. Второе это оператор запятая, потому всё корректно. Третье, четвёртое и шестое (по аналогии с 3м), очевидно 🎧, тоже CE. Пятое по аналогии со вторым OK.
Учитывая все эти кейсы, вероятно стоит всегда инициализировать ваши переменные с помощью фигурных скобок. Просто чтобы избавиться от вероятных проблем.
Из интересного ещё следующий момент. В C++11 следующая запись означала
std::initializer_list<int>{1}:auto i{1};Однако в C++14 семантику подобного изменили, где это стало
int{1}.
auto i = {1};А что же тут? Это без сомнений
init_list. Т.е. вы меняете тип объекта при инициализации с помощью =. Конечно интуитивно это вроде понятно, но кринж🥴, не правда ли? Говорят, что семантику такого поправлять не будут. Может просто запретят что-то такое делать в будущем (или нет, who knows). Мб потому стоит ещё и отказаться от инициализации с помощью =. Просто на всякий случай. Хотя есть аргумент за такой стиль. У вас будет одинаковый способ “инициализации” переменных и типов:
auto x = …;
using T = …;Для типов тогда лучше явно указывайте тип:
auto i = int{1} (это всё мысли из AAA от Herb Sutter). В защиту такого подхода приводится поинт, что вы не забудете инициализировать вашу переменную. Хотя и тут есть траблы:std::string x = “1”;
auto x = “1”s; // C++14Вот эту
s в конце (литерал) очень легко забыть/не обратить на неё внимания. Ещё можно заметить, что такой способ работает (работал*) только для movable/copyable типов, иначе CE:
auto a = std::atomic<int>{9}; // CE before C++17Ну и всякие другие проблемы бывают. Например с производительностью некоторых типов.
Чисто из опыта совет: помните, что значит первая буква в AAA — Almost. Потому что иногда поиск типа переменной становится неприятным муторным занятием, попросту тратящим время.
Ещё классический момент это инициализация вектора:
std::vector<int> v(3, 1); // 1 1 1
std::vector<int> v{3, 1}; // 3 1Ну тут всё понятно. Не будем обсуждать.
В докладе Nicolai Josuttis можно посмотреть про это всё счастье подробнее. Там ещё много маслин словить можно.