array + struct: extra curly brackets required for initialization?

Are extra curly brackets really required when initialize structures comparing with primitive types? It's kind of inconsistent design, can someone help explain?

1. array with primitive type e.g int can be initialized with:
 
struct<int, 3> i {1,2,3};


2. however, with struct Point (example below), seems need extra curly brackets:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include <iostream>
#include <array> 
using namespace std;

struct Point {int x,y;};

ostream& operator<<(ostream& os, Point p){
    return os<<'{'<<p.x<<','<<p.y<<'}';
}

int main()  {
    //array<Point, 3> a = {{1,1},{2,2},{3,3}}; won't work!
    array<Point, 3> a = {{{1,1},{2,2},{3,3}}};
    for(int i=0; i!=a.size();++i){        
        cout << a[i] << '\n';
    }
    cout << a.front();
    cout << a.back();
    return  1;
}
Last edited on
Btw, book "The C++ Programming Language" 4th edition page 208 (Section 8.2.4) uses code below:
 
Array points {{1,2},{3,4},{5,6}};


Which causes error in my VScode with message: too many initializer values
...
Hmm, you can use
array<Point, 3> a = { Point{1,1}, Point{2,2}, Point{3,3} };

Maybe it's because an array<> is a fixed-size container, so you can't use an initialiser-list constructor like other containers.

If you use a vector instead then the following will work:
vector<Point> a = { {1,1}, {2,2}, {3,3} };

I must admit, I have never found the array<> class very useful. Other linear containers - particularly vectors and valarrays - are much more flexible.
Last edited on
Hello howardcheng,

I am not sure and this is more of a guess at the moment. If I am misunderstanding it someone will say so.

1
2
3
4
5
6
array<Point, 3> a
{  // <--- To initialize the whole
    {  // <--- Maybe because each element is a struct?
        { 1, 1 }, { 2, 2 }, { 3, 3 }   // <--- To initialize the 3 structs of each element of the array.
    } 
};


Just a thought for now.

Andy
I'm with lastchance re use of array. Can't remember the last time I used it. And now there is span in C++20. begin()/end()/size() already work fine with c-style array in scope. And if you pass a c-style array to a function, use a template to get the size(s).
Consider using c-style array:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <iterator>
using namespace std;

struct Point { int x, y; };

ostream& operator<<(ostream& os, const Point& p) {
	return os << '{' << p.x << ',' << p.y << '}';
}

template <size_t N>
void display(const Point(&arr)[N])
{
	for (const auto& p : arr)
		cout << p << '\n';
}

int main() {
	const Point a[] {{1,1}, {2,2}, {3,3}};

	for (int i = 0; i != size(a); ++i)
		cout << a[i] << '\n';

	cout << '\n';

	display(a);

	cout << '\n';
	cout << *begin(a) << "  ";
	cout << *rbegin(a) << '\n';
}

From the book "The C++ Programming Language" 4th edition page 208 (Section 8.2.4)

1
2
3
4
5
6
7
8
9
10
#include <iostream>

struct Point { int x, y; };

struct Array { Point elem[3]; };

int main()
{
	Array points2 {{1, 2}, {3, 4}, {5, 6}};
}


This doesn't compile either - even if using a C++14 compiler for which the book uses.

If you use clang, you first get the warning

warning: suggest braces around initialization of subobject


then the error.

To fix this issue, an extra set of brackets is indeed needed

1
2
3
4
5
6
7
8
9
10
#include <iostream>

struct Point { int x, y; };

struct Array { Point elem[3]; };

int main()
{
	Array points2 {{{1, 2}, {3, 4}, {5, 6}}};
}


But:

1
2
3
4
5
6
7
8
9
#include <iostream>
#include <vector>

struct Point { int x, y; };

int main()
{
	std::vector<Point> points2 {{1, 2}, {3, 4}, {5, 6}};
}


compiles OK.

Can some one explain this in terms of the standard??
Last edited on
This is my take on it.

A std::vector can be constructed with an initializer list. So, a list of Point objects can be used herre.

The Array struct contains a Point[3] array. If you were creating a Point[3] on the stack, it would be:
Point elem[3] = {{1, 2}, {3, 4}, {5, 6}};

Because you actually want to create an Array object which contains a Point[3], you need to create the Point[3] as PART of the Array creation.

To paraphrase @HandyAndy:

1
2
3
4
5
6
Array points2
{  // <--- To initialize the Array object
    {  // <--- To initialize the elem[3] within the Array
        { 1, 1 }, { 2, 2 }, { 3, 3 }   // <--- To initialize the 3 structs of each element of the array.
    } 
};
This issue with needing an extra set of braces when initializing a std::array has been around since the container was introduced in C++11. Other containers don't need them:

https://stackoverflow.com/questions/14178264/c11-correct-stdarray-initialization

Maybe because std::array is an aggregate, unlike the other containers?

https://en.cppreference.com/w/cpp/language/aggregate_initialization

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
#include <vector>

struct Point
{
   int x;
   int y;
};

std::ostream& operator<<(std::ostream& os, Point p)
{
   return os << '{' << p.x << ',' << p.y << '}';
}

int main()
{
   std::vector<Point> vec { {1, 1}, {2, 2}, {3, 3} };

   for (auto const& itr : vec)
   {
      std::cout << itr << '\n';
   }
   std::cout << '\n';

   std::cout << vec.front() << ' ' << vec.back() << '\n';
}
howardcheng wrote:
Which causes error in my VScode with message: too many initializer values

I get the same error with Visual Studio 2019 without the extra set of braces. A bit ironic when it really seems to mean there are not enough initializer values.

BTW, why are you returning 1 in main? Any non-zero return status 'tells the OS' the program didn't end successfully.

https://stackoverflow.com/questions/22604196/difference-between-return-1-return-0-return-1-and-exit

I usually omit the return statement in main. If the program doesn't have a problem it returns 0 anyway.
I will take the advice from lastchance
array<Point, 3> a = { Point{1,1}, Point{2,2}, Point{3,3} };

this looks more comfortable :)
Actually, my advice would be to use a vector - it's more flexible.
Topic archived. No new replies allowed.