【发布时间】:2017-04-17 04:47:04
【问题描述】:
假设我有一个在编译时已知大小的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):我也有一个不可默认构造的类型,所以我需要在数组初始化时计算实际值。然而,与这个问题相反,对我来说,这些值不仅是索引的函数,而且是前面值的函数。与一系列函数调用相比,我可以更轻松地使用循环来构建我的值。所以我在一个循环中构造元素并将它们放在一个向量中,然后我想使用该向量的最终状态来初始化数组。
以上似乎编译和工作正常,但也许有办法改进它。
- 也许我可以巧妙地利用一些我不知道的标准库功能。
- 也许我可以通过某种方式避免使用辅助函数。
- 也许我可以以某种方式将其表述为与元素的移动语义而不是上面使用的复制语义一起使用。
- 也许我可以使用
operator[]来避免随机访问,而只使用前向迭代器语义,这样它也适用于std::set或std::forward_list作为输入。 - 也许我应该停止使用
std::vector,而是使用std::array<std::optional<T>, N>来表达我的目标,使用C++17 或其他等效实现。
相关问题:
- Copy std::vector into std::array 不假定没有默认构造函数的类型,因此在默认初始化后复制在那里是可行的,但对我来说不可行。
- Populate std::array with non-default-constructible type (no variadic templates) 独立地从其索引计算每个元素,因此它试图避免中间容器。答案使用可变参数模板,即使标题要求避免使用它们。
【问题讨论】:
-
有趣的问题,但这闻起来很糟糕。为什么要生成数据然后复制它们?这是由于您希望将它们打包在
std::array中,但与原始std::vector相比,它有什么优势?两者都将数据保存在连续的内存中,因此前者应该没有后者的优势。唯一的区别是size是一个编译时变量,但无论如何都是这样。 -
@Walter:有效问题。一方面,我的原件是
std::set,所以无论如何我至少需要转换一次。我也在使用转换构造函数对元素执行类型转换。所以这不仅仅是保留std::vector的问题。不过我可以用一个。反对的主要论据可能是我的感觉,即编译器知道的越多,它就可以优化得越好。我在实践中只处理 24 个元素,虽然这对于完整的循环展开来说可能太多了,但它可以例如展开四人一组,知道计数可以被 4 整除。只是一种感觉。
标签: c++ stl initialization c++14 stdarray