用一个范围(一对迭代器)初始化 std::array [英] Initialize std::array with a range (pair of iterators)

查看:27
本文介绍了用一个范围(一对迭代器)初始化 std::array的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如何从一个范围(由一对迭代器定义)初始化 std::array?

How can I initialize an std::array from a range (as defined by a pair of iterators)?

像这样:

vector<T> v;
...
// I know v has exactly N elements (e.g. I just called v.resize(N))
// Now I want a initialized with those elements
array<T, N> a(???);  // what to put here?

我认为 array 会有一个带有一对迭代器的构造函数,这样我就可以做 array<T, N>a(v.begin(), v.end()),但它似乎根本没有构造函数!

I thought array would have a constructor taking a pair of iterators, so that I could do array<T, N> a(v.begin(), v.end()), but it appears to have no constructors at all!

我知道我可以将向量copy到数组中,但我宁愿直接用向量内容初始化数组,而不是先默认构造它.我该怎么办?

I know I can copy the vector into the array, but I'd rather initialize the array with the vector contents directly, without default-constructing it first. How can I?

推荐答案

使用随机访问迭代器,并假设在编译时具有特定大小,您可以使用 索引包这样做:

With random access iterators, and assuming a certain size at compile-time, you can use a pack of indices to do so:

template <std::size_t... Indices>
struct indices {
    using next = indices<Indices..., sizeof...(Indices)>;
};
template <std::size_t N>
struct build_indices {
    using type = typename build_indices<N-1>::type::next;
};
template <>
struct build_indices<0> {
    using type = indices<>;
};
template <std::size_t N>
using BuildIndices = typename build_indices<N>::type;

template <typename Iterator>
using ValueType = typename std::iterator_traits<Iterator>::value_type;

// internal overload with indices tag
template <std::size_t... I, typename RandomAccessIterator,
          typename Array = std::array<ValueType<RandomAccessIterator>, sizeof...(I)>>
Array make_array(RandomAccessIterator first, indices<I...>) {
    return Array { { first[I]... } };
}

// externally visible interface
template <std::size_t N, typename RandomAccessIterator>
std::array<ValueType<RandomAccessIterator>, N>
make_array(RandomAccessIterator first, RandomAccessIterator last) {
    // last is not relevant if we're assuming the size is N
    // I'll assert it is correct anyway
    assert(last - first == N); 
    return make_array(first, BuildIndices<N> {});
}

// usage
auto a = make_array<N>(v.begin(), v.end());

这假设编译器能够省略中间副本.我认为这个假设不是什么大问题.

This assumes a compiler capable of eliding the intermediate copies. I think that assumption is not a big stretch.

实际上,它也可以使用输入迭代器来完成,因为花括号初始化器列表中每个元素的计算在下一个元素的计算之前进行排序(第 8.5.4/4 节).

Actually, it can be done with input iterators as well, since the computation of each element in a braced-init-list is sequenced before the computation of the next element (§8.5.4/4).

// internal overload with indices tag
template <std::size_t... I, typename InputIterator,
          typename Array = std::array<ValueType<InputIterator>, sizeof...(I)>>
Array make_array(InputIterator first, indices<I...>) {
    return Array { { (void(I), *first++)... } };
}    

由于 *first++ 中没有任何 I,我们需要一个虚拟的 I 来激发包扩展.逗号运算符来救援,使用 void() 来消除有关缺乏效果的警告,并防止逗号过载.

Since *first++ doesn't have any I in it, we need a dummy I to provoke the pack expansion. Comma operator to the rescue, with void() to silence warnings about lack of effects, and also preventing overloaded commas.

这篇关于用一个范围(一对迭代器)初始化 std::array的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆