I have an alias to a static size array, it's very simple to use:
using triplet_t = std::uint8_t[3];
// vvvvvvvvvvvvvvvvvv <--- más fácil que std::uint8_t(&triplet)[3]
void f(const triplet_t &triplet) { /* whatever */ }
triplet_t t{}; // Tan bueno como std::uint8_t t[3]{};
t[0] = '0';
t[1] = '1';
t[2] = '2';
for (auto &v : t) std::cout << v << ' ';
std::cout << '\n';
// Todo correcto...
triplet_t t3[3]{};
for (auto &r : t3)
for(auto &v : r)
v = 42;
I can even use the alias in containers:
std::vector<triplet_t> vt;
Or so I thought, because the moment you use it vt
fails:
vt.push_back({});
GCC 8.0.0 201711
error: parenthesized initializer in array new [-fpermissive] { ::new((void *)__p) _Up(std::forward<_Args>(__args)...); } ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ error: request for member '~unsigned char [3]' in '* __p', which is of non-class type 'unsigned char [3]' destroy(_Up* __p) { __p->~_Up(); } ~~~~~~^~~
The problem seems to be that after unrolling all the template wizardry a placement-new is called which is passed the parameters in parentheses, and this is obviously not the way to initialize a statically sized array.
Also, somehow the container thinks it triplet_t
's an object and so asks for a destructor, again failing to compile. The problem obviously persists without the alias:
std::vector<std::uint8_t[3]> vt;
vt.push_back({}); // Mal!
vt.push_back({255, 0, 0}); // Error!
But there is no problem if an object with the same memory representation is used:
struct rgb { std::uint8_t r, g, b; };
std::vector<rgb> vt;
vt.push_back({}); // Bien!
vt.push_back({255, 0, 0}); // Genial!
I wonder why this happens. Is there a way to save statically sized arrays in containers?
In the C++ standard: 26.2.1 General container requirements it is specified that all containers in the standard library require their element types to be "Erasable" , which is not true for an array.
And regarding the second part of the question:
Could you do:
Fixed-size arrays cannot be used inside a container because the container imposes several requirements on the type used:
The type must support the copy constructor (or move syntax in its absence) in addition to the corresponding assignment operator.
In the case of fixed-size arrays, this feature does not exist and can be verified with a simple example:
The best alternative is, as @asdasdasd has proposed , to use
std::array
since it implements the characteristics of a fixed-size array without having to suffer from its limitations.However, if someone insists on using a fixed-size array, the solution is to use a wrapper that allows you to evade the restrictions:
Its mechanics are very simple:
The basic definition of the wrapper is incomplete, so it won't compile. The only specialization that works, at the moment, is the one that handles an array of size
SIZE
. This wrapper comes prepared to offer the basic functionality:[]
.Its use is quite simple:
And it even supports initializations by initialization list:
And this can be tested with simple code:
You can see the example workingaqui
As I have indicated on other occasions, this type of wrappers has the advantage that the compiler is capable of eliminating them when generating the final code, so their impact in terms of performance is 0.