使用std :: vector进行std ::数组初始化
Use std::vector for std::array initialization
假设我的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
}
该应用程序类似于带有非默认构造类型的填充std ::数组(无variadic模板):我也有一种不默认构造的类型,因此我需要在时间计算实际值数组被初始化。但是,与这个问题相反,对我而言,这些值不仅是索引的函数,而且是前面值的函数。与一系列函数调用相比,我可以更轻松地构建我的值。因此,我在循环中构造元素并将它们放在向量中,然后我想使用该向量的最终状态来初始化数组。
以上似乎编译和工作正常,但也许有一些改进的方法。
- 也许我可以巧妙地使用一些我不知道的标准库功能。
- 也许我可以避免以某种方式避免使用辅助功能。
- 也许我可以以某种方式对此进行表达,以便它可以与上述元素的移动语义作用,而不是上面使用的副本语义。
- 也许我可以避免使用
operator[]
的随机访问,而是仅使用Forward Iterator语义,因此它也适用于std::set
或std::forward_list
作为输入。 - 也许我应该停止使用
std::vector
,而是使用std::array<std::optional<T>, N>
,使用C 17或一些等效的实现来表达我的目标。
相关问题:
- 复制std :: vector中的std :: array不假定没有默认构造函数的类型,因此在那里可行,但在我的默认初始化后复制。
- 带有非默认构造类型(无variadic模板)的填充std ::数组,该数组独立地从其索引中计算每个元素,因此它试图避免使用中间容器。答案即使标题请求避免了它们。 ,也使用variadic模板。
我会提出:
template<typename T, typename Iter, std::size_t... Is>
constexpr auto to_array(Iter& iter, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{ ((void)Is, *iter++)... }};
}
template<std::size_t N, typename Iter,
typename T = typename std::iterator_traits<Iter>::value_type>
constexpr auto to_array(Iter iter)
-> std::array<T, N> {
return to_array<T>(iter, std::make_index_sequence<N>{});
}
这将从迭代器中推论元素类型,并将复制VS-MOVE语义留在呼叫者&ndash;如果呼叫者想移动,他们可以通过std::move_iterator
等选择加入:
auto initFoos() {
constexpr unsigned n{123};
std::vector<Foo> lst;
for (unsigned i{}; i != n; ++i) {
lst.push_back(getNextFoo(lst));
}
// copy-init array elements
return to_array<n>(lst.cbegin());
// move-init array elements
return to_array<n>(std::make_move_iterator(lst.begin()));
}
在线演示
编辑:如果要覆盖所述的元素类型,如评论中所示,那么我建议:
template<typename T, typename Iter, std::size_t... Is>
constexpr auto to_array(Iter& iter, std::index_sequence<Is...>)
-> std::array<T, sizeof...(Is)> {
return {{ ((void)Is, T(*iter++))... }};
}
template<std::size_t N, typename U = void, typename Iter,
typename V = typename std::iterator_traits<Iter>::value_type,
typename T = std::conditional_t<std::is_same<U, void>{}, V, U>>
constexpr auto to_array(Iter iter)
-> std::array<T, N> {
return to_array<T>(iter, std::make_index_sequence<N>{});
}
这使元素类型可选,但使其成为第二个参数,而不是第一个参数,因此用法看起来像to_array<N, Bar>(lst.begin())
而不是to_array<Bar, N>(lst.begin())
。
相关文章:
- 初始化具有非默认构造函数的std::数组项的更好方法
- 如何在旧c++中初始化const-std向量
- 在main()之外初始化std::vector会导致性能下降(多线程)
- 为什么std::vector和std::valarray初始化构造函数不同
- 使用通用值初始化 std::map,不重复
- std::initializer_list,大括号初始化和标头
- 标准::unordered_map 中的 std::array 的值初始化
- 使用 std::index_sequence 初始化具有固定大小数组成员的 POD 结构容器
- 初始化 std::vector 替换为单大括号而不是双大括号
- 包含 std::list 的结构体的 C++ 初始化
- 在构造函数中使用可变参数初始化 std::tuple
- 使用 std::分配器在 constexpr 中进行默认初始化
- 使用大括号初始化 std::vector 使用初始值设定项列表
- 为什么初始化 std::vector 时不能使用模板整数?
- 使用 std::ios_base::Init 正确初始化全局变量
- 如何在构造函数参数中初始化"std::set"?
- 初始化 std::数组 of Eigen::Map
- C++ - std::构造函数中的矢量初始化
- C STD ::初始化类对象中的Alloc错误错误
- std::初始化列表中的数组初始值设定项列表初始化