21

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?

arrayできるように、イテレータのペアを取るコンストラクタがあると思いましたが、コンストラクタarray<T, N> a(v.begin(), v.end())がまったくないようです。

ベクトルを配列に入れることができることはわかっていますがcopy、最初にデフォルトで構築することなく、ベクトルの内容で配列を直接初期化したいと思います。どうやって?

4

3 に答える 3

24

ランダム アクセス イテレータを使用し、コンパイル時に特定のサイズを想定すると、インデックスのパックを使用してこれを行うことができます。

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()、効果の欠如に関する警告を黙らせ、コンマのオーバーロードを防ぎます。

于 2012-06-07T10:33:27.987 に答える
5

お気づきのように、 std::array にはコンストラクターがまったくありません (コンパイラーが生成したデフォルトのコンストラクターを除く)。

これは意図的に行われたため、C 配列のように静的に初期化できます。静的初期化子なしで配列を埋めたい場合は、データをコピーする必要があります。

于 2012-06-07T09:57:38.810 に答える
4

次のように使用できます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

ここで、最後の行は次のように展開されます。

std::array<int,5> a = {v[0], v[1], v[2], v[3], v[4]}; //EXPANDED LINE

これはあなたが望むものです。

于 2012-06-07T12:31:16.833 に答える