3

Consider the following C++11 code:

#include <initializer_list>

struct MyStruct {
    MyStruct() {}
    MyStruct(const MyStruct& other) {}
    void doStuff() const {}
};

int main() {
    MyStruct a;
    auto b{a};

    a.doStuff();
    b.doStuff();
    return 0;
}

I was expecting b to be an instance of MyStruct, copy-constructed from a, but instead, b is an std::initializer<MyStruct> when compiled with GCC 4.9.1. GCC 8.2 compiles this as expected.

NOTE I made an example of this on Godbolt: https://godbolt.org/z/adNDoO

Could you please explain the difference between the two compiler versions? (Or what the standard states for that matter?)

Victor
  • 13,914
  • 19
  • 78
  • 147

2 Answers2

2

This was a bug in C++11 fixed in C++14. It looks like the GCC 8.2 is taking into consideration the new rules for braced-init-list (N3922) even if you are compiling with C++ 11 flag.

The new roles say:

For direct list-initialization:

  • For a braced-init-list with only a single element, auto deduction will deduce from that entry;
  • For a braced-init-list with more than one element, auto deduction will be ill-formed.

In your case:

MyStruct a;
auto b{a};

It follows the first rule, that's why it compiles with no problem.

The older generation of GCC 4.9.1 does not implement these new rules, so that's why by default it consider it an std::initializer_list.

Community
  • 1
  • 1
mohabouje
  • 3,867
  • 2
  • 14
  • 28
0

This is the expected behavior since in C++ 11:

A std::initializer_list object is automatically constructed when: ... a braced-init-list is bound to auto, including in a ranged for loop

So when you assign {x1, x2, ..., xn} to an 'auto' you get the object of type of std::initializer_list<decltype(x1)> if all values have the same type (I'm skipping here references and cv for simplicity ):

auto a = {5};   // std::initializer_list<int>
auto b {5};     // std::initializer_list<int>
auto c = {1, 2}; // std::initializer_list<int>
auto d {1, 2};   // std::initializer_list<int>

However in C++17 this was changed. The following rules were added:

  • for copy list initialization auto deduction will deduce a std::initializer_list if all elements in the list have the same type, or be ill-formed.
  • for direct list initialization auto deduction will deduce a T if the list has a single element, or be ill-formed if there is more than one element.

So when you compile with C++17 conformant compiler you will get

auto a = {42};   // std::initializer_list<int>
auto b {42};     // int
auto c = {1, 2}; // std::initializer_list<int>
auto d {1, 2};   // error, too many

I believe that gcc 8.2 doesn't process -std=c++11 for this situation properly

Dmitry Gordon
  • 2,229
  • 12
  • 20