为什么初始化器列表只能在声明时使用?

Sem*_*aki 14 c++ arrays initializer-list

可以使用所谓的初始化列表来初始化数组。

例如:

int my_array[3] = {10, 20, 30};
Run Code Online (Sandbox Code Playgroud)

当我们为数组设置一组初始值时,这非常有用。但是,这种方法一旦声明就无法为数组分配新值。

my_array = {10, 20, 30};

error: assigning to an array from an initializer list
Run Code Online (Sandbox Code Playgroud)

但是,有时我们有一些过程需要将数组初始化为一些初始值(例如,在循环内),因此我认为能够使用初始化列表将值分配给已声明的变量将非常有用。

我的问题是:是否有理由在声明时拥有这种功能,但一旦声明数组就没有?为什么在一种情况下有效,而在另一种情况下无效?

L. *_* F. 22

数组是C ++中的二等公民。它们对象,但是受到严格限制:它们不能被复制,它们在各种上下文中都会退化为指针,等等。考虑使用std::array,这是内置数组之上的(固定大小)包装器,但是第一个支持各种便利功能的一流公民:

std::array<int, 3> my_array = {10, 20, 30};
my_array = {40, 50, 60};
Run Code Online (Sandbox Code Playgroud)

这样做是因为,每[array.overview] / 2

std::array是一个聚合类型,最多可以将N其类型转换为的元素进行列表初始化T

live demo

这也适用于std::vector。向量是一个不同的故事,因此在这里我不再赘述。


如果您希望坚持使用内置数组,这是我设计的一种变通办法,它可以使用模板元编程技术为内置数组分配值列表(尊重值类别)。如果数组的长度和值列表不匹配,则会(正确)引发编译时错误。(感谢Caleth的评论指出了这一点!)请注意,在C ++中不可能复制内置数组。这就是为什么我们必须将数组传递给函数。

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)...);
}
Run Code Online (Sandbox Code Playgroud)

并使用它:

int arr[3] = {10, 20, 30};
assign(arr, 40, 50, 60);
Run Code Online (Sandbox Code Playgroud)

现在arr由组成40, 50, 60

live demo