When to Use the Brace-Enclosed Initializer

C++ error: Array must be initialized with a brace enclosed initializer

The syntax to statically initialize an array uses curly braces, like this:

int array[10] = { 0 };

This will zero-initialize the array.

For multi-dimensional arrays, you need nested curly braces, like this:

int cipher[Array_size][Array_size]= { { 0 } };

Note that Array_size must be a compile-time constant for this to work. If Array_size is not known at compile-time, you must use dynamic initialization. (Preferably, an std::vector).

When to use the brace-enclosed initializer?

I think the following could be a good guideline:

  • If the (single) value you are initializing with is intended to be the exact value of the object, use copy (=) initialization (because then in case of error, you'll never accidentally invoke an explicit constructor, which generally interprets the provided value differently). In places where copy initialization is not available, see if brace initialization has the correct semantics, and if so, use that; otherwise use parenthesis initialization (if that is also not available, you're out of luck anyway).

  • If the values you are initializing with are a list of values to be stored in the object (like the elements of a vector/array, or real/imaginary part of a complex number), use curly braces initialization if available.

  • If the values you are initializing with are not values to be stored, but describe the intended value/state of the object, use parentheses. Examples are the size argument of a vector or the file name argument of an fstream.

array must be initialized with a brace-enclosed initializer c++

In this declaration

Personne join_p{stoi(n),name,s};

the data member of the structure Personne is declared like

char nom[10];

that is it is an array,

But the array name used as an initializer is implicitly converted to a pointer to its first element.

So you are trying to initialize an array with a pointer.

You may not initialize an array with a pointer. You need to copy the array name into the array join_p.nom.

Pay attention to that the array name does not contain a string but it seems that the data member nom must contain a string.

In any case this loop

for (int i = 0; i < nom.length(); i++){
name[i] = nom[i];
}

is unsafe because you can write outside the array name.

It would be better that initially the data member nom of the structure had the type std::string.

Also these statements

Personne join_p{stoi(n),name,s};
p = &join_p;

do not make a great sense because the pointer p is not used anywhere within or outside the function except this assignment.

C: Array initialization requires a brace-enclosed initializer list - simple code


When using char walk[10][10] = { 0 }; I get the compiler error "C: Array initialization requires a brace-enclosed initializer list".

That is your compiler being terribly anal-retentive.

The statement in question is perfectly legal C. It defines a 10x10 2-D array of char named walk where every element (of 100) is 0.

To comply with your compiler whims, use one of

char walk[10][10] = { { 0, 0, 0, 0, 0, 0, 0, 0, 0 },  /* ..., */ { 0, 0, 0, 0, 0, 0, 0, 0, 0 } };
char walk[10][10] = { { 0 }, { 0 } };
char walk[10][10] = { { 0 } };
char walk[10][10] = { 0 }; // initial statement wrongly rejected by compiler

Even better (IMHO) would be to configure your compiler to accept legal code.

godbolt.org accepts your initial code

Automatic generation of a brace-enclosed initializer list in C++ using language features (NOT pre-processor directives)

Like this:

#include <array>
#include <memory>
#include <utility>

template <std::size_t ...I>
std::array<std::shared_ptr<int>, sizeof...(I)> foo(std::index_sequence<I...>)
{
return {(void(I), std::make_shared<int>())...};
}

std::array<std::shared_ptr<int>, 4> array_ = foo(std::make_index_sequence<4>());

Guaranteed copy elision from C++17 ensures that the array is constructed in place, and no extra moves happen.

The return statement expands to {(void(0), std::make_shared<int>()), (void(1), std::make_shared<int>())...}. void(...) is not strictly necessary, but Clang emits a warning otherwise.


But if it was my code, I'd write a more generic helper instead:

#include <utility>

template <typename R, typename N, typename F, N ...I>
[[nodiscard]] R GenerateForEach(std::integer_sequence<N, I...>, F &&func)
{
return {(void(I), func(std::integral_constant<N, I>{}))...};
}

template <typename R, auto N, typename F>
[[nodiscard]] R Generate(F &&func)
{
return (GenerateForEach<R, decltype(N)>)(std::make_integer_sequence<decltype(N), N>{}, std::forward<F>(func));
}

Then:

auto array_ = Generate<std::array<std::shared_ptr<int>, 4>, 4>([](auto){return std::make_shared<int>();});

While the lambda discards the index in this case, it often ends up being useful, especially given that in [](auto index){...}, index.value is constexpr.

c++ error: array must be initialized with a brace-enclosed initializer

You can't use C arrays like other variables or objects in many cases. You can't pass a C array by value to a function or return a C array from a function. It will decay to a pointer to the first element. Therefore std::array was introduced in C++. It does exactly what you expected from C arrays in your code:

#include <array>

constexpr int V = 4;

auto floydWarshall(std::array<std::array<int, V>, V> graph){
for (int k = 0; k < V; k++) {
for (int i = 0; i < V; i++) {
for (int j = 0; j < V; j++) {
if (graph[i][k] + graph[k][j] < graph[i][j])
graph[i][j] = graph[i][k] + graph[k][j];
}
}
}
return graph;
}

With std::array you can pass a copy of the array to the function and don't need to copy it manually. You can return a copy of the array instead of using dynamic memory allocation and pointers.

You use the function with

auto dist = floydWarshall(graph);

where graph has type std::array<std::array<int, V>, V>.

Initialize a class with brace-enclosed initializer list

Initializer lists are more appropriate for situations where the size of the list is dynamic. In your case, where the size of Vec is a template parameter (i.e. static), you're probably better off with variadic parameters:

template <unsigned C>
struct Vec
{
Vec(){}

template<typename ... V>
Vec(V ... args)
{
static_assert(sizeof...(V) == C, "");
//...
}
};

then these will work:

Vec<3> myVec2;
myVec2 = {1, 2, 3};
Vec<3> myVec3 = {1,2,3};

But this one won't, as it explicitly requires an std::initializer_list:

Vec<3> myVec1{{1,2,3}};

brace-enclosed initializer list conversion error

The errors are narrowing conversions, which are never allowed in uniform initializers.

That's relevant because aggregate initialization existed all along and did not have that restriction. Now in C++11 world, aggregate initialization is just a form of uniform initialization, with ditto narrowing rules.

You should explicitly convert the respective values (checking that the conversion is safe!)

E.g.

struct X { short i; };

int init = 42;
X x{init}; // not ok

Explicitly converting makes it ok:

X x{static_cast<short>(init)}; // ok

Why do brace-enclosed initializer lists not work for std::array

Here is working solution - you need double braces for arrays.

int main()
{
const vector<Widget> vw = {
{"vw1", {1,2,3}},
{"vw2", {1,2,3}} };
const array<Widget,2> aw = {{
{"aw1", {1,2,3}},
{"aw2", {1,2,3}} }};
const vector<Object> vo = {
{"vo1", {1,2,3}},
{"vo2", {1,2,3}} };
const array<Object,2> ao = {{
{"ao1", {1,2,3}},
{"ao2", {1,2,3}} }};
return 0;
}

Why?

http://en.cppreference.com/w/cpp/container/array

std::array is a container that encapsulates fixed size arrays.
This container is an aggregate type with the same semantics as a struct holding a C-style array T[N] as its only non-static data member. Unlike a C-style array, it doesn't decay to T* automatically. As an aggregate type, it can be initialized with aggregate-initialization given at most N initializers that are convertible to T: std::array a = {1,2,3};.

Theoretical implementation (it is more complicated in reality)

template <typename T, size_t size> 
struct array
{
T data[size];
}

So first brace is to aggregate-initializate array object on its own, second brace to aggregate-initializate internal "legacy C style" array.



Related Topics



Leave a reply



Submit