使用随机访问迭代器,并在编译时假设某个大小,您可以使用一组索引来执行此操作:
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());
这假定编译器能够删除中间副本。我认为这个假设并不是一个很大的延伸。
实际上,它也可以使用输入迭代器来完成,因为花括号初始化列表中每个元素的计算在下一个元素的计算之前进行排序(第 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()
消除有关缺乏效果的警告,并防止逗号过载。