Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

error C3074: an array can only be initialized with an initializer-list

I am working on a petty (pretty) printer for PODs, STLs and Composite Types like Arrays. While doing so, I was also fiddling with Initialization Lists and came across the following declaration

std::vector<double[3]> arr{ { 10, 11, 12 }, { 20, 21, 22 } }; 

It seems both VC2013 and G++ 4.8 is not quite happy and issues a consistent error message which in either case is not quite helpful to me

For VC++: error C3074: an array can only be initialized with an initialize-list

For G++ 4.8: error: array must be initialized with a brace-enclosed initialize

So either Initialization lists cannot be used here or my syntax is quite not right?

On a similar front, the following syntax seems to be valid

std::vector<std::array<int, 3>>  arr{ { 10, 11, 12 }, { 20, 21, 22 } };

What is the possible problem with my initialization list?

  • Note I understand I should use std::array instead of C type arrays but I am just experimenting.
  • Note If you wan't to play around with this, here is an IDEONE version
  • Note Also, it would be quite beneficial if you can refer me back to the standard.
like image 802
Abhijit Avatar asked Aug 15 '14 16:08

Abhijit


1 Answers

Reading the current C++1y draft standard.

From before Table 99:

T is EmplaceConstructible into X from args , for zero or more arguments args , means that the following expression is well-formed: allocator_traits::construct(m, p, args)

Table 100:

X(il);              |  Equivalent to      | X(il.begin(), il.end());
--------------------+---------------------+--------------------------------
X(i, j);            |                     | Requires:
X a(i, j);          |                     | T shall be EmplaceConstructible
                                          | into X from *i.

So std::vector<double[3]> v{ {1,2,3}, {4,5,6} }; is valid iff double[3] is EmplaceConstructible from {1,2,3} as an element of an initializer list being passed to a std::vector<double[3]>.

There is a clause about forward iterators as well, but that is no problem (as std::initialzier_list iterators are forward iterators).

std::vector<T> takes an std::initializer_list<T> parameter.

So std::initializer_list<double[3]> is the candidate list.

First, std::initializer_list<double[3]> x = {{1.0, 2.0, 3.0}}; fails to compile in gcc. But suppose that is a bug in gcc.

Second, ::new (nullptr) double[3](std::initializer_list<double>{1.0, 2.0, 3.0}); placement new, which EmplaceConstructable reduces to in the lack of a suitable construct override, fails to compile.

So double[3] is not EmplaceConstruble from a std::initalizer_list<double> nor from a double[3] nor anything else (as the error occurs because I used a bracket, not because of what was in the brackets, in the placement new), unless the allocator does magic I am not aware of to avoid the placement new.

Thus your code violates the current draft standard, and probably C++11, and certainly C++03 (which had stricter requirements on containers).

like image 181
Yakk - Adam Nevraumont Avatar answered Sep 19 '22 10:09

Yakk - Adam Nevraumont