使用std :: vector进行std :: array初始化

时间:2016-12-02 10:01:55

标签: c++ stl initialization c++14 stdarray

假设我在编译时已知有std::vector大小,我想将其转换为std::array。我该怎么办?是否有标准功能来执行此操作?

到目前为止,我所拥有的最佳解决方案是:

template<class T, std::size_t N, class Indexable, std::size_t... Indices>
std::array<T, N> to_array_1(const Indexable& indexable, std::index_sequence<Indices...>) {
  return {{ indexable[Indices]... }};
}

template<class T, std::size_t N, class Indexable>
std::array<T, N> to_array(const Indexable& indexable) {
  return to_array_1<T, N>(indexable, std::make_index_sequence<N>());
}

std::array<Foo, 123> initFoos {
  std::vector<Foo> lst;
  for (unsigned i = 0; i < 123; ++i)
    lst.push_back(getNextFoo(lst));
  return to_array<Foo, 123>(lst); // passing lst.begin() works, too
}

应用程序类似于Populate std::array with non-default-constructible type (no variadic templates):我也有一个不是默认构造的类型,所以我需要在数组初始化时计算实际值。然而,与该问题相反,对我来说,这些值不仅仅是指数的函数,而且也是前面值的函数。我可以使用循环而不是一系列函数调用来更轻松地构建我的值。所以我在循环中构造元素并将它们放在向量中,然后我想使用该向量的最终状态来初始化数组。

以上似乎编译和工作正常,但也许有办法改进它。

  1. 也许我可以巧妙地使用一些我不知道的标准库功能。
  2. 也许我可以以某种方式避免帮助函数。
  3. 也许我可以某种方式表达这一点,使其适用于元素的移动语义,而不是上面使用的复制语义。
  4. 也许我可以避免使用operator[]进行随机访问,而只是使用前向迭代器语义,因此它也适用于std::setstd::forward_list作为输入。
  5. 也许我应该停止使用std::vector,而是使用std::array<std::optional<T>, N>代替,使用C ++ 17或一些等效的实现来表达我的目标。
  6. 相关问题:

1 个答案:

答案 0 :(得分:3)

我建议:

template<typename T, typename Iter, std::size_t... Indices>
std::array<T, sizeof...(Indices)> to_array(Iter iter, std::index_sequence<Indices...>) {
    return {{((void)Indices, *iter++)...}};
}

template<typename T, std::size_t N, typename Iter>
std::array<T, N> to_array(Iter iter) {
    return to_array<T>(std::move(iter), std::make_index_sequence<N>{});
}

这会将copy-vs-move语义留给调用者 - 如果调用者想要移动,他们可以通过std::move_iterator等选择加入:

auto initFoos() {
    std::vector<Foo> lst;
    for (unsigned i{}; i != 123u; ++i) {
        lst.push_back(getNextFoo(lst));
    }
    // copy-init array elements:
    return to_array<Foo, 123>(lst.cbegin());
    // or move-init array elements:
    return to_array<Foo, 123>(std::make_move_iterator(lst.begin()));
}

Online Demo