Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why I can't desalinize std::array like this? [duplicate]

Why I can't desalinize std::array like this?

#include <array>

struct Point
{
    float x;
    float y;
};

int main()
{
   std::array<Point, 3> m_points { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
   };
}

Doing this I get error:

error: too many initializers for std::array<Point, 3ul>

but it works like this:

std::array<Point, 3> m_points { 
   Point{ 1.0f, 1.0f }, 
   Point{ 2.0f, 2.0f }, 
   Point{ 3.0f, 3.0f } 
};

In contrast std::map can be initialized with both ways written below:

   std::map<int, int> m1 {std::pair<int, int>{1,2}, std::pair<int, int>{3,4}}; 
   std::map<int, int> m2 {{1,2}, {3,4}};
like image 974
Narek Avatar asked Sep 05 '16 08:09

Narek


2 Answers

In this declaration and initialization

   std::array<Point, 3> m_points { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
   };

the compiler considers the first initializer in braces like the initializer of the whole array (of the internal aggregate). std::array is an aggregate that contains another aggregate.

Write instead

   std::array<Point, 3> m_points {
      { 
      { 1.0f, 1.0f }, 
      { 2.0f, 2.0f }, 
      { 3.0f, 3.0f }
      }
   };

In the second case

std::array<Point, 3> m_points { 
   Point{ 1.0f, 1.0f }, 
   Point{ 2.0f, 2.0f }, 
   Point{ 3.0f, 3.0f } 
};

each initializer is considered sequentially as an initializer of a next element of the internal aggregate.

Consider this simple demonstrative program.

#include <iostream>

struct array
{
    int a[10];
};

int main()
{
    array a = { { 0, 0 }, { 1, 1 } };

    return 0;
}

The compiler issues an error like

prog.cpp:14:33: error: too many initializers for 'array'
  array a = { { 0, 0 }, { 1, 1 } };
                                 ^

That is it decided that { 0, 0 } is an initializer of the internal array (internal aggregate). Thus the next initializer in braces does not have a corresponding data member in the outer aggregate (structure).

like image 145
Vlad from Moscow Avatar answered Nov 19 '22 17:11

Vlad from Moscow


std::array has no explicitly defined constructors, unlike other standard containers such as std::vector or std::map, but only the automatically provided constructors. With std::vector, the compiler will try to match your expression against each available constructor and for a construct like

std::vecor<Point> m_points { {1.0f,1.0f}, {2.0f,2.0f}, {3.0f,3.0f} };

finds a match with the constructor

std::vector::vector(initializer_list<T>, const Allocator& = Allocator() );

But with std::array, it must use aggregate initialisation of the underlying array (Point[3] in your case) and hence your construction does not match. To get it to work, you must add another pair of braces

std::array<Point, 3> m_points { 
  { { 1.0f, 1.0f },
    { 2.0f, 2.0f }, 
    { 3.0f, 3.0f } }
};
like image 43
Walter Avatar answered Nov 19 '22 15:11

Walter