79

const std::vector<const T>likeを作成して初期化const T a[] = { ... }して固定 (および少数) の値にするエレガントな方法はありますか?
を期待する関数を頻繁に呼び出す必要がありvector<T>ますが、私の場合、これらの値は決して変更されません。

原則として、私は次のようなことを考えました

namespace {
  const std::vector<const T> v(??);
}

v はこのコンパイル単位の外では使用されないためです。

4

10 に答える 10

61

C++11 の場合:

vector<int> luggage_combo = { 1, 2, 3, 4, 5 };

元の答え:

そのためには、C++0x を待つか、Boost.Assignなどを使用する必要があります。

例えば:

#include <boost/assign/std/vector.hpp>
using namespace boost::assign; // bring 'operator+=()' into scope

vector<int> v;
v += 1,2,3,4,5;
于 2008-10-23T20:56:10.093 に答える
39

const ベクトルを初期化して興味深い内容にする方法を尋ねている場合、答えはおそらくコピー コンストラクターを使用することです。最初に苦労してベクトルを入力し、それから新しい const ベクトルを作成します。または、コンストラクター テンプレートを使用して、vector<InputIterator>(InputIterator, InputIterator)他の種類のコンテナーまたは配列から初期化することもできます。配列の場合、それは初期化リストで定義されている可能性があります。

このようなものは、うまくいけばあなたが望むものに近いです:

const T ra[3] = {t1, t2, t3};
const vector<const T> v(ra, ra+3);

ベクトルを取る関数に const ベクトルを渡す方法を尋ねている場合、答えは次のいずれかです。

  • 関数がベクトルを変更する可能性があり、オブジェクト/参照が const であるため、できません。オリジナルの非 const コピーを作成し、それを渡します。

また

  • const_cast非定数ベクトルを取るが、たまたまベクトルを変更しないことがわかっている関数に渡すために、定数を削除するために使用します。

後者は、それを見た人がゴーグルについて、そして彼らが何もしないという事実についてコメントする原因となるものの 1 つです。それはまさにそのためのものですが、必要な場合はすでに負けているconst_castというかなり強力な議論があります。const_cast

これらの両方を行うこと (コピー コンストラクターを使用して非定数ベクトルから非定数ベクトルを作成し、次に定数をキャストすること) は間違いなく間違っています。非定数ベクトルを使用する必要がありました。したがって、これらのいずれかを選択してください...

[編集:vector<T>との違いについて話していることに気付きましたconst vector<const T>。残念ながら STL では、vector<const T>vector<T>はまったく無関係な型であり、それらの間で変換する唯一の方法はコピーすることです。これはベクトルと配列の違いです - aは黙って安全に]T**に変換できます。const T *const *

于 2008-10-23T21:04:17.457 に答える
15

短くて汚い方法 (Boost に似ていますlist_of())

#include <iostream>
#include <vector>
#include <iterator>
#include <algorithm>
using namespace std;

template <typename T>
struct vlist_of : public vector<T> {
    vlist_of(const T& t) {
        (*this)(t);
    }
    vlist_of& operator()(const T& t) {
        this->push_back(t);
        return *this;
    }
};

int main() {
    const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
    copy(v.begin(), v.end(), ostream_iterator<int>(cout, "\n"));
}

現在、C++11 には初期化リストがあるため、そのようにする必要はなく、Boost を使用する必要さえありません。ただし、例として、次のように C++11 で上記をより効率的に実行できます。

    #include <iostream>
    #include <vector>
    #include <utility>
    #include <ostream>
    using namespace std;

    template <typename T>
    struct vlist_of : public vector<T> {
        vlist_of(T&& t) {
            (*this)(move(t));
        }
        vlist_of& operator()(T&& t) {
            this->push_back(move(t));
            return *this;
        }
    };

    int main() {
        const vector<int> v = vlist_of<int>(1)(2)(3)(4)(5);
        for (const auto& i: v) {
            cout << i << endl;
        }
    }

operator=(vlist_of&&)ただし、ベクトルが定義されていないため、C++11 初期化子リストを使用するほど効率的ではありません。

次のように変更された tjohns20 の方法は、より良い c++11 である可能性がありますvlist_of

#include <iostream>
#include <vector>
#include <utility>
using namespace std;

template <typename T>
class vlist_of {
    public:
        vlist_of(T&& r) {
            (*this)(move(r));
        }
        vlist_of& operator()(T&& r) {
            v.push_back(move(r));
            return *this;
        }
        vector<T>&& operator()() {
            return move(v);
        }
    private:
        vector<T> v;
    
};

int main() {
    const auto v = vlist_of<int>(1)(2)(3)(4)(5)();
    for (const auto& i : v) {
        cout << i << endl;
    }
    
}
于 2008-10-31T16:38:34.593 に答える
12

他の人が言ったように、ソース配列へのポインタを渡さない限り、C スタイルの配列を初期化できるのと同じ方法でベクトルを初期化することはできません。しかし、その場合、ベクトルがグローバルな const である場合、代わりに古い C スタイルの配列を使用してみませんか?

const int MyInts[] = {
1, 2, 3, 4, 5};

const size_t NumMyInts = sizeof(MyInts)/sizeof(MyInts[0]);

const ベクトルに対してアルゴリズムを使用するのと同じ方法で、この配列に対して STL アルゴリズムを使用することもできます...

const int* myInt = std::find( &MyInts[0], &MyInts[NumMyInts], 3);
于 2008-10-23T21:06:45.563 に答える
6

次の 2 つの手順で実行できます。

namespace {
    const T s_actual_array[] = { ... };
    const std::vector<const T> s_blah(s_actual_array,
        s_actual_array + (sizeof(s_actual_array) / sizeof(s_actual_array[0])));
}

あなたが望むほど美しくはないかもしれませんが、機能的です。

于 2008-10-23T21:25:21.457 に答える
5

どうですか:

int ar[]={1,2,3,4,5,6};
const int TotalItems = sizeof(ar)/sizeof(ar[0]);
std::vector<int> v(ar, ar+TotalItems);
于 2012-05-04T09:40:38.020 に答える
0

私があなたを正しく理解したかどうかはわかりません。あなたの質問は次のように理解しています。ベクトルを多数の要素に初期化したいのです。push_back()ベクトルで使用することの何が問題になっていますか? :-)

格納する要素の数がわかっている場合 (または格納する要素が次の 2 の累乗未満であることが確実な場合)、X 型のポインターのベクトルがある場合 (ポインターでのみ機能します)、これを行うことができます。

std::vector< X* > v;
v.reserve(num_elems);
X* p = v.begin();
for (int count = 0; count < num_elems; count++)
   p[count] = some_source[count];

を使用していても、次の 2 の累乗以上の要素を追加しないように注意してくださいpush_back()。へのポインタv.begin()は無効になります。

于 2008-10-23T21:10:42.327 に答える
0

Shadow2531 の応答に基づいて、Shadow のソリューションのように std::vector から実際に継承することなく、このクラスを使用してベクトルを初期化しています

template <typename T>
class vector_init
{
public:
    vector_init(const T& val)
    {
        vec.push_back(val);
    }
    inline vector_init& operator()(T val)
    {
        vec.push_back(val);
        return *this;
    }
    inline std::vector<T> end()
    {
        return vec;
    }
private:
    std::vector<T> vec;
};

使用法:

std::vector<int> testVec = vector_init<int>(1)(2)(3)(4)(5).end();

Steve Jessop のソリューションと比較すると、より多くのコードが作成されますが、配列の作成がパフォーマンス クリティカルでない場合は、配列を 1 行で初期化する良い方法だと思います。

于 2011-05-09T16:45:13.803 に答える
0

それらがすべて同じであれば、あなたはただ行うことができます

vector<T> vec(num_items, item);

しかし、そうではないと思います-その場合、おそらく最もきちんとした方法は次のとおりです。

vector<T> vec(num_items);
vec[0] = 15;
vec[1] = 5;
...

C++0x では、まさにあなたが考えている方法でイニシャライザ リストを使用できますが、残念ながら、現時点ではあまり適切ではありません。

于 2008-10-23T21:35:50.187 に答える