Arrays can be initialized with what's called an initialization list.
Eg:
int my_array[3] = {10, 20, 30};
That's very useful when we have a set of initial values for our array. However this approach doesn't work to assign new values to the array once it's declared.
my_array = {10, 20, 30};
error: assigning to an array from an initializer list
However sometimes we have processes where we need to initialize our arrays several times to some initial values (eg: inside a loop) so I think it would be very useful to be able to use initializer lists to assign values to variables already declared.
My question is: Is there a reason for having such a feature at declaration time but not once the array is declared? Why does it work in one case but not in the other case?
Arrays are second-class citizens in C++.
They are objects,
but they are severely restricted:
they can't be copied,
they are decayed into pointers in various contexts, etc.
Consider using std::array
,
which is a (fixed-size) wrapper on top of builtin arrays,
but is a first-class citizen which supports various convenience features:
std::array<int, 3> my_array = {10, 20, 30};
my_array = {40, 50, 60};
This works because, per [array.overview]/2,
std::array
is an aggregate type that can be list-initialized with up toN
elements whose types are convertible toT
.
This also works with std::vector
.
Vectors are a different story,
so I am not going to go into details here.
If you prefer to insist on builtin arrays, here's a workaround I designed to enable assigning a list of values to a builtin array (respecting value categories), using template metaprogramming techniques. A compile-time error is (correctly) raised if the length of the array and the value list mismatch. (Thanks to Caleth's comment for pointing this out!) Note that copying builtin arrays is impossible in C++; that's why we have to pass the array to the function.
namespace detail {
template <typename T, std::size_t N, std::size_t... Ints, typename... Args>
void assign_helper(T (&arr)[N], std::index_sequence<Ints...>, Args&&... args)
{
((arr[Ints] = args), ...);
}
}
template <typename T, std::size_t N, typename... Args>
void assign(T (&arr)[N], Args&&... args)
{
return detail::assign_helper(arr, std::make_index_sequence<N>{}, std::forward<Args>(args)...);
}
And to use it:
int arr[3] = {10, 20, 30};
assign(arr, 40, 50, 60);
Now arr
consists of 40, 50, 60
.