web-dev-qa-db-ja.com

C ++、コンパイル時にstd :: mapを静的に初期化できますか?

これをコーディングすると

std::map<int, char> example = {
                                (1, 'a'),
                                (2, 'b'),
                                (3, 'c') 
                              };

その後、g ++が私に言います

deducing from brace-enclosed initializer list requires #include <initializer_list>
in C++98 ‘example’ must be initialized by constructor, not by ‘{...}’   

コンストラクターはランタイムであり、理論的には失敗する可能性があるため、それは少し私を悩ませます。

確かに、もしそうなら、すぐに失敗し、一貫してそうする必要があるので、私は問題を素早く見つけて修正するべきです。

しかし、それでも、私は興味があります-とにかくコンパイル時にマップ、ベクターなどを初期化する必要はありますか?


編集:私は組み込みシステム向けに開発していると言っていたはずです。すべてのプロセッサーにC++ 0xコンパイラーがあるわけではありません。最も人気のあるものはおそらくそうなりますが、私は落とし穴に遭遇したくないし、コードの2つのバージョンを維持する必要があります。

Boostについては、私は未定です。彼らは、組み込みシステムでの有限状態マシンクラスの使用について希望がわからないので、実際にここでコーディングしているのは、イベント/状態/ Fsmクラスです。

ため息、私はそれを安全にプレイした方が良いと思いますが、この議論が他の人にとって役立つことを願っています。

40
Mawg

C++ 98にはありません。 C++ 11はこれをサポートしているため、C++ 11フラグを有効にしてg ++が示唆するものを含めると、できます。

編集:gcc 5からC++ 11はデフォルトでオンになっています

21
Artyom

静的な初期化ではありませんが、試してみてください。コンパイラがC++ 0xをサポートしていない場合は、std :: mapの反復コンストラクターを使用します。

std::pair<int, std::string> map_data[] = {
    std::make_pair(1, "a"),
    std::make_pair(2, "b"),
    std::make_pair(3, "c")
};

std::map<int, std::string> my_map(map_data,
    map_data + sizeof map_data / sizeof map_data[0]);

これは非常に読みやすく、追加のライブラリを必要とせず、すべてのコンパイラで動作するはずです。

37
Dmitry

Boost.Assign ライブラリを使用できます:

#include <boost/assign.hpp>
#include <map>
int main()
{
   std::map<int, char> example = 
      boost::assign::map_list_of(1, 'a') (2, 'b') (3, 'c');
}

ただし、Neilなどが以下のコメントで指摘したように、UncleBeanの提案と同様に、この初期化は実行時に行われます。

14
mloskot

C++ 0xでは、中括弧をすべて使用する必要がある場合があります(各ペアにも新しいスタイルの構文を使用します)。

std::map<int, char> example = { {1,'a'}, {2, 'b'}, {3, 'c'} };

ペアを構成するこれらの括弧は意味がありません。または、各ペアを完全に指定するか、make_pairを使用できます(C++ 98で行うように)

std::map<int, char> example = {
    std::make_pair(1,'a'),
    std::make_pair(2, 'b'),
    std::make_pair(3, 'c')
};

コンパイル時にこれらのインスタンスを作成する場合:いいえ。 STLコンテナはすべて、ランタイムメモリ管理を完全にカプセル化します。

私は、boostのメタプログラミングのようなライブラリを備えたコンパイル時マップのみを本当に持っていると思います(それが完全に正しい場合、100%確信がなく、何が良いかを研究していません):

using namespace boost::mpl;
map<
    pair<integral_c<int, 1>, integral_c<char, 'a'> >,
    pair<integral_c<int, 2>, integral_c<char, 'b'> >,
    pair<integral_c<int, 3>, integral_c<char, 'c'> >
> compile_time_map;
13
UncleBens

C++ 0x以前では、実行時に使用するために設計されたコンテナを使用しないこと(および基本型と集約に制限する)

_struct pair { int first; char second; };
pair arr[] = {{1,'a'}, {2,'b'}}; // assuming arr has static storage
_

これは、何らかの種類のmap viewを使用してアクセスするか、または Boost。配列 はありません。

もちろん、問題は、メリットがこれを実装する時間を正当化するかどうかです。

ここで私の読みが正しい場合、C++ 0x initializer-listsmayは_std::map_や_std::pair_。ただし、動的初期化と比較してセマンティクスが変わらない場合のみ。
このように、それは私には思えますあなたの実装が振る舞いが静的解析を介して検証できる場合にのみあなたが求めたものを得ることができます」 mapが静的に初期化された場合に変更されますが、それが起こる保証はありません。

4
Georg Fritzsche

使用できるトリックがありますが、このデータが他の静的コンストラクターで使用されない場合のみです。まず、次のような単純なクラスを定義します。

typedef void (*VoidFunc)();
class Initializer
{
  public:
    Initializer(const VoidFunc& pF)
    {
      pF();
    }
};


次に、次のように使用します。

std::map<std::string, int> numbers;
void __initNumsFunc()
{
  numbers["one"] = 1;
  numbers["two"] = 2;
  numbers["three"] = 3;
}
Initializer __initNums(&__initNumsFunc);


もちろんこれは少しやり過ぎですので、本当に必要な場合にのみ使用することをお勧めします。

1
Adis H

コンパイル時にstd::mapを初期化する標準的な方法はありません。他の人が述べたように、C++ 0xではコンパイラは可能であれば初期化を静的に最適化できますが、それは保証されません。

ただし、STLは単なるインターフェース仕様であることを忘れないでください。独自の準拠コンテナを作成し、静的な初期化機能を付与できます。

コンパイラとSTL実装(特に組み込みプラットフォーム)のアップグレードを計画しているかどうかによっては、使用している実装を掘り下げ、派生クラスを追加して、それらを使用することさえできます。

1
Potatoswatter