В GCC7 реализован последний стандарт С++17 (будет принят в этом году). Хотелось бы обратить внимание, что изменились правила вывода типа auto при фигурной инициализации.

С++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)


  1. xandox
    13.01.2017 16:02

    auto x1 = { 1, 2 }; // ошибка: невозможно наличие нескольких элементов при фигурной инициализации auto


    В обще-то x1 будет std::initializer_list, что бы случилась ошибка, должно быть
    auto x{1, 2};
    


  1. sborisov
    13.01.2017 16:02

    Смотрите Proof — это ссылка на стандарт.

    auto x1 = { 1, 2 }; // error: cannot have multiple elements in a braced-init-list with auto
    


    1. xandox
      13.01.2017 16:05
      +1

      Да, я уже посмотрел, но похоже там ошибка
      во-первых вот тут по другому http://en.cppreference.com/w/cpp/language/template_argument_deduction#Other_contexts, ну или по ссылке ошибка.
      во-вторых — это странно, таким образом получается intitializer_list никак не создать.


      1. sborisov
        13.01.2017 16:17

        Никакой ошибки нет ни там ни там.
        Т.к. объект только создаётся в обоих случаях будет вызван конструктор.
        Эти варианты эквиваленты и сгенерируют абсолютно одинаковый ассемблерный код.

        auto x{1, 2};
        auto x1 = { 1, 2 };
        
        


        1. xandox
          13.01.2017 16:26

          В 11/14 — да, это одно и тоже, но суть прделожения которое в статье описывается как раз в том, что бы сделать их разными. КМК
          Если второй вариант будет давать ошибку, то и такой код должен давать ошибку

          for (auto x: {1, 2, 3}) { }
          


          1. sborisov
            13.01.2017 16:37

            11/14 тут непричём. Я же написал:

            Т.к. объект только создаётся в обоих случаях будет вызван конструктор


            1. xandox
              13.01.2017 16:43

              Я же написал:
              Т.к. объект только создаётся в обоих случаях будет вызван конструктор



              Все верно, только нужно понять конструктор какого типа?
              И так как второй вариант это не прямая инициализация, то логично было бы создавать initializer_list, как и во всех остальных случаях.


          1. sborisov
            13.01.2017 16:38

            В статье написано, что нужно сделать одинаковым

            auto x = 1; 
            auto x{1};
            


      1. saluev
        13.01.2017 16:19
        -1

        Кажется, что между стандартом и cppreference.com приоритет за стандартом.


        1. xandox
          13.01.2017 16:21

          ну ок, вот ссылка на предложение
          http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html
          там в примерах то же самое написано.


      1. sborisov
        13.01.2017 16:22

        получается intitializer_list никак не создать.


        Cоздавайте на здоровье
        auto x = std::initializer_list<int>{1,2,3};
        


        1. xandox
          13.01.2017 16:27

          Ну так да, но в таком случаи и можно без auto и = вообще обойтись. Но не об этом же речь.


    1. xandox
      13.01.2017 16:38

      А, я понял в чем проблема, у нас ссылки на разные предложения. В одном так, в другом эдок. Понятно теперь.
      Я опирался на ту которая на clang.llvm.org. и cppreference похоже ту да же смотрит.


      1. xandox
        13.01.2017 16:47
        +1

        Как не странно, но сайте gcc ссылка на тот же предложение что и у clang
        http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3922.html

        В общем все правильно написано на cppreference, а у вас в статье ссылка на старое предложение которое изменилось.


        1. sborisov
          13.01.2017 17:05

          Спасибо! Поправил статью.


    1. VadimVP
      13.01.2017 16:43

      Proof по ссылке это не стандарт, а очень старая версия предложения.
      То что попало в стандарт (см. свежую версию черновика) совпадает с cppreference.


      1. sborisov
        13.01.2017 16:54

        Спасибо! Поправил статью.


    1. Antervis
      13.01.2017 17:00

      значит, ошибка в компиляторе


  1. lookid
    13.01.2017 16:19
    -4

    #define auto do{ raise(SIGSEGV); }while(0);

    Я пофиксил.


  1. 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-ого года


    1. sborisov
      13.01.2017 17:00

      Да, я уже обновил статью и ссылки. Спасибо.