HC4*_*ica 19 c++ arrays range stdvector c++11
如何std::array从范围初始化(由一对迭代器定义)?
像这样的东西:
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?
Run Code Online (Sandbox Code Playgroud)
我以为array会有一个构造函数接受一对迭代器,所以我可以做array<T, N> a(v.begin(), v.end()),但它似乎根本没有构造函数!
我知道我可以copy将矢量放入数组中,但我宁愿直接用矢量内容初始化数组,而不是先默认构造它.我怎么能够?
R. *_*des 21
使用随机访问迭代器,并在编译时假定一定大小,您可以使用一组索引来执行此操作:
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());
Run Code Online (Sandbox Code Playgroud)
这假定编译器能够删除中间副本.我认为这个假设并不是一个很大的延伸.
实际上,也可以使用输入迭代器来完成,因为在计算下一个元素(第8.5.4/4节)之前,对braced-init-list中的每个元素的计算进行了排序.
// 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++)... } };
}
Run Code Online (Sandbox Code Playgroud)
由于*first++没有任何I内容,我们需要一个假人I来激发包装扩展.逗号操作员进行救援,void()以沉默警告缺乏效果,并防止过载逗号.
就像你注意到的那样,std :: array根本没有构造函数(编译器生成的默认构造函数除外).
这是故意完成的,因此可以像C数组一样静态初始化.如果要在没有静态初始化程序的情况下填充数组,则必须复制数据.
您可以用作BOOST_PP_ENUM:
include <boost/preprocessor/repetition/enum.hpp>
#define INIT(z, i, v) v[i]
std::vector<int> v;
//fill v with at least 5 items
std::array<int,5> a = { BOOST_PP_ENUM(5, INIT, v) }; //MAGIC
Run Code Online (Sandbox Code Playgroud)
这里,最后一行扩展为:
std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE
Run Code Online (Sandbox Code Playgroud)
这就是你想要的。