2017-10-11 10 views
3

私はstd::vectorを、いくつかの要素がデフォルトのコンストラクタではなく特定のコンストラクタによって構築されているように構築したいと考えています。言い換えれば、私はベクトルを構築しながら要素を置き換えたいと思う。どうやってやるの?std :: vectorの構築中に要素をemplaceする方法は?

thisを考えてみましょう:

struct Item 
{ 
    Item(double) {} 
    Item(const Item&) = delete; 
    Item(Item&&) = delete; 
}; 
std::vector<Item> vv(10, 3.14); // Fails! Tries to copy while I want to emplace. 
+0

おそらく、ベクターが間違ったコンテナですが、代わりに['std :: array'](http://en.cppreference.com/w/cpp/container/array)を使うべきでしょうか?あるいは、あなたはあなたが持っている*実際の問題について詳しく調べることができますか? *なぜ*あなたはあなたが助けたい解決策を考案しましたか?これは非常に典型的な[XY問題](https://meta.stackexchange.com/questions/66377/what-is-the-xy-problem)タイプの質問です。 –

+1

@Someprogrammerdude実際には 'std :: vector'や' std :: array'ではなく、組み込みの動的配列は目的に最も適したデータ構造です(動的ではあるが固定サイズで、変更はありません)。しかし、組み込みの動的配列は、この* emplace-while-constructing *機能をサポートしていません。 – Vahagn

+0

"動的配列"(私はあなたが[*可変長配列*](https://en.wikipedia.org/wiki/Variable-length_array)を意味すると思います)は標準のC++では存在しません。いずれかの選択肢。それとも新しい[]を意味しますか?そしておそらくあなたが持っているオリジナルの問題*は別の方法で解決できますか? –

答えて

6

あなたItemクラスはコピーや移動をサポートしていません。これにより、std::vector::reserveおよびstd::vector::resizeを含むstd::vectorのほとんどの操作がコンパイルされなくなります。実際にそのようなクラスがある場合は、代わりにstd::vector<std::aligned_storage_t<sizeof(Item), alignof(Item)>>が必要です。

あなたはItemに移動コンストラクタを追加することができれば、あなたはヘルパー関数の代わりに(あなたが使用しているコンストラクタのオーバーロードは、コピーの観点で定義されている)を作成することができます。以下のバージョンは単項のコンストラクタでのみ動作することに注意してください。

template <typename T, typename Arg> 
auto make_vector(std::size_t n, Arg&& arg) 
{ 
    std::vector<T> result; 
    result.reserve(n); 

    for(std::size_t i = 0; i < n; ++i) 
     result.emplace_back(arg); 

    return result; 
} 

使用法:

auto vec = make_vector<Item>(10, 3.14); 
+0

ノンオンのコンマを使った折り畳み式は素晴らしかったです。それは編集履歴でさえない:/ –

+0

@BartekBanachewicz:それは間違ったことをしていた:P –

+0

ああ。 D –

3

次の2つのイテレータを取るベクトルのコンストラクタを使用することができます。たとえば、vector<double>のイテレータを使用できます。

std::vector<double> init(10, 3.14); 
std::vector<Item> vv(init.begin(), init.end()); 

Live demo

それとも、初期化を行うために、独自のカスタムイテレータクラスを書くことができ:

struct ItemInitializer { 
    int index; 
    double value; 

    using value_type = double; 
    using difference_type = int; 
    using pointer = const double*; 
    using reference = const double&; 
    using iterator_category = std::forward_iterator_tag; 

    ItemInitializer() : index(0), value(0.0) {} 
    ItemInitializer(int index, double v = 0.0) : index(index), value(v) {} 

    bool    operator!=(const ItemInitializer& other) const { return other.index != index; } 
    ItemInitializer& operator++() { index++; return *this; } 
    ItemInitializer operator++(int) { ItemInitializer ret(index, value); index++; return ret; } 
    const double& operator*() const { return value; } 
    const double* operator->() const { return &value; } 
}; 

std::vector<Item> vv(ItemInitializer{0, 3.14}, ItemInitializer{10}); 

Live demo

関連する問題