С++11, С++14 — при выводе типа использовали следующие правила:
int foo(){
return 1;
}
auto x = foo(); // x = int
auto x{foo()}; // x = initializer_list<int>
Разница между обычной и фигурной инициализизацией была неинтуитивной и странной. Также это выглядело неинтуитивно при инициализируюшем захвате.
Скотт Майерс обращает внимание на это в своей книге.
[x = foo()](){} // x = int
[x{foo()}](){} // x = initializer_list<int>
Вывод типа возвращаемого значения, частично решал эту проблему.
auto f()
{
return {1,2}; // ошибка вывода типа, {1,2} не является корректным выражением
}
Но ситуация проявляется вновь, в случае отдельной переменной auto
auto f()
{
auto x{1,2}; // x = initializer_list<int>
return x; // возвращается как initializer_list, при попытке доступа возникает неопределённое поведение
}
В С++17 для фигурной инициализации правила отныне такие:
1. При фигурной инициализации только с одним элементом, тип будет выведен из типа этого элемента.
auto x { 1 }; // x = int
2. При фигурной инициализации с несколькими элементами, вывод будет невозможным.
auto x1 { 1, 2 }; // ошибка: невозможно наличие нескольких элементов при фигурной инициализации auto
3. При фигурной инициализации с одним или несколькими элементами и присваиванием тип будет выведен как std::initializer_list
auto x = { 1, 2 }; // x = std::initializer_list<int>
> Предложение
> Standard draft — 7.1.7.4.1 Placeholder type deduction
P.S. В комментариях выяснили, что попавшее в стандарт изменение, немного отличается от изначального предложения. Поправил статью.
Комментарии (21)
sborisov
13.01.2017 16:02Смотрите Proof — это ссылка на стандарт.
auto x1 = { 1, 2 }; // error: cannot have multiple elements in a braced-init-list with auto
xandox
13.01.2017 16:05+1Да, я уже посмотрел, но похоже там ошибка
во-первых вот тут по другому http://en.cppreference.com/w/cpp/language/template_argument_deduction#Other_contexts, ну или по ссылке ошибка.
во-вторых — это странно, таким образом получается intitializer_list никак не создать.sborisov
13.01.2017 16:17Никакой ошибки нет ни там ни там.
Т.к. объект только создаётся в обоих случаях будет вызван конструктор.
Эти варианты эквиваленты и сгенерируют абсолютно одинаковый ассемблерный код.
auto x{1, 2}; auto x1 = { 1, 2 };
xandox
13.01.2017 16:26В 11/14 — да, это одно и тоже, но суть прделожения которое в статье описывается как раз в том, что бы сделать их разными. КМК
Если второй вариант будет давать ошибку, то и такой код должен давать ошибку
for (auto x: {1, 2, 3}) { }
sborisov
13.01.2017 16:3711/14 тут непричём. Я же написал:
Т.к. объект только создаётся в обоих случаях будет вызван конструктор
xandox
13.01.2017 16:43Я же написал:
Т.к. объект только создаётся в обоих случаях будет вызван конструктор
Все верно, только нужно понять конструктор какого типа?
И так как второй вариант это не прямая инициализация, то логично было бы создавать initializer_list, как и во всех остальных случаях.
xandox
13.01.2017 16:38А, я понял в чем проблема, у нас ссылки на разные предложения. В одном так, в другом эдок. Понятно теперь.
Я опирался на ту которая на clang.llvm.org. и cppreference похоже ту да же смотрит.xandox
13.01.2017 16:47+1Как не странно, но сайте gcc ссылка на тот же предложение что и у clang
http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html
В общем все правильно написано на cppreference, а у вас в статье ссылка на старое предложение которое изменилось.
VadimVP
13.01.2017 16:43Proof по ссылке это не стандарт, а очень старая версия предложения.
То что попало в стандарт (см. свежую версию черновика) совпадает с cppreference.
Antervis
13.01.2017 16:59Отставить панику! Смотрим стандарт, 7.1.7.4.1:
auto x1 = { 1, 2 }; // decltype(x1) is std::initializer_list<int> auto x2 = { 1, 2.0 }; // error: cannot deduce element type auto x3{ 1, 2 }; // error: not a single element auto x4 = { 3 }; // decltype(x4) is std::initializer_list<int> auto x5{ 3 }; // decltype(x5) is int
Поменялись только пункты 3 и 5. Инициализация списка как в варианте 1 осталась.
Proof
Глупо использовать в качестве пруфа ссылку на документ 13-ого года
xandox
В обще-то x1 будет std::initializer_list, что бы случилась ошибка, должно быть