web-dev-qa-db-ja.com

構造体を値として取るマップをどのように初期化しますか?

IDの連想配列->値としてマップを使用しています。値はオブジェクトを定義する構造体です。

#include <map>

struct category {
        int id;
        std::string name;
};

std::map<int, category> categories;

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};

}

上記のコードはg ++でコンパイルされますが、次の警告が表示されます。

warning: extended initializer lists only available with -std=c++0x or -std=gnu++0x

構造体の初期化に関するさまざまな質問と回答をここで読みましたが、まだ少し混乱しています。関連する一連の質問があります。

  1. コンパイラオプション-std = c ++ 0xを追加して警告を表示することもできますが、根本的な問題についてはまだ賢明ではありません。カテゴリ構造体にメソッドを追加すると、問題が発生しませんか?

  2. このPOD構造体(カテゴリ)をよりC++ 03に準拠した方法で初期化する最良の方法は何ですか?

  3. 基本的に、私は物事を別の方法ではなくある方法で行うことの結果をまだ確信していません。この種類の連想配列(キーはオブジェクトのIDです)はPHPでは簡単ですが、C++でこれを行う適切な方法についてはまだ学んでいます。上記のコードのコンテキストで注意すべき点はありますか?

編集
次の質問は関連していますが、最初に読んだときの答えがわかりませんでした:
C++初期化匿名構造体
配列としてメンバーとして構造体を初期化するc ++
C++で構造体を初期化しています

17
augustin

C++(ISO/IEC 14882:2003)では、中括弧で囲まれた式のリストを使用して、それを定義する宣言でaggregate型の変数を初期化できます。

例えば。

struct S { int a; std::string b; };

S x = { 39, "Hello, World\n" };

aggregate型は、ユーザーが宣言したコンストラクター、プライベートまたは保護された非静的データメンバー、基本クラス、仮想関数のない配列またはクラスです。クラスaggregateはPODクラスである必要はなく、配列はaggregateであり、それが配列であるタイプが集約であるかどうかは関係ありません。

ただし、中かっこで囲まれた式のリストは、集計の初期化子としてのみ有効であり、割り当てやクラスコンストラクターのメンバー初期化リストなどの他のコンテキストでは通常許可されません。

C++の次のバージョン(C++ 0x)の現在のドラフトでは、ブレースで囲まれた式のリスト(brace-init-list)がより多くのコンテキストで許可され、オブジェクトがそのようなオブジェクトから初期化される場合initializer listそれはlist-initializationと呼ばれます。

このようなリストが許可される新しいコンテキストには、関数呼び出し、関数の戻り値、コンストラクターへの引数、メンバーおよび基本初期化子、および割り当ての右側に引数が含まれます。

つまり、これはC++ 03では無効です。

int main() {
        categories[1] = {1, "First category"};
        categories[2] = {2, "Second category"};
}

代わりに、このようなことを行うことができます。

int main() {
        category tmp1 = { 1, "First category" };
        category tmp2 = { 2, "Second category" };

        categories[1] = tmp1;
        categories[2] = tmp2;
}

あるいは。

int main() {
        category tmpinit[] = { { 1, "First category" },
                               { 2, "Second category" } };
        categories[1] = tmpinit[0];
        categories[2] = tmpinit[1];
}

または、タイプに応じてファクトリ関数を作成することもできます。 (型のコンストラクターを追加することもできますが、これによりクラスが非集約になり、他の場所で集約の初期化を使用できなくなります。)

category MakeCategory( int n, const char* s )
{
    category c = { n, s };
    return c;
}

int main()
{
    categories[1] = MakeCategory( 1, "First category" );
    categories[2] = MakeCategory( 2, "Second category" );
}
20
CB Bailey

現在のC++標準では、初期化リストを使用して、POD値のみを含む配列および構造体を初期化できます。次の標準(別名C++ 0xまたはC++ 1x)では、非PODタイプを含む構造体で同じことを行うことができます。 std :: string。それが警告です。

IDと名前を取得し、代わりにそのコンストラクターを呼び出すだけの単純なコンストラクターをcategoryに追加することをお勧めします。

#include <map>
#include <string>

struct category {
        category() : id(0), name() {}
        category(int newId, std::string newName)
         : id(newId), name(newName) {}

        int id;
        std::string name;
};

std::map<int, category> categories;

int main() {
        categories[1] = category(1, "First category");
        categories[2] = category(2, "Second category");

}
10
Mephane

これは古いことは知っていますが、使用することもできます

std::map<int, std::pair<std::string, int>> categories

または:

std::map<int, std::Tuple<std::string, int, double>> categories

もっと必要な場合。

3
AKJ

私たちが使用している初期化の種類は、C++ 0xと呼ばれる新しいC++標準でのみ導入されているため、警告とコンパイラオプションがあります。一部のコンパイラは、g ++として、すでにいくつかの新機能をサポートしていますが、標準自体はまだ受け入れられていません。私たちが知っているように、C++には多くの新機能が追加されています。詳細は Stroustrupのサイト を参照してください。

構造を初期化するには、(自然に)ctorを追加できます。

struct category {
        category(int i, const std::string& n): id(i), name(n) {}
        int id;
        std::string name;
};

次に、次のようにマップを初期化します。

categories[1] = category(1, "First category");

const char*から文字列への暗黙的な変換がここで機能することに注意してください。そうでない場合は、const char*を使用してctorを定義することもできます。

3
davka

必要な機能はC/C++ではaggregateと呼ばれます。 「aggregate c ++」を検索すると、その理由と方法を詳しく説明した多くの情報が見つかります。

1-カテゴリ構造体にメソッドを追加すると、問題が発生しませんか?

メソッドが基礎となるC++メモリレイアウトに影響を与えない限り、必要ありません。たとえば、プレーン関数は重要ではありませんが、クラス関数の前に配置される可能性が高いため、仮想関数は重要です。

2-このcOD構造体(カテゴリ)をよりc99に準拠した方法で初期化する最良の方法は何ですか?

他のレスポンダが示唆するようにコンストラクタを使用します。

3-上記のコードのコンテキストで注意すべき点はありますか?

コンストラクターの設計方法によっては、冗長なコピーが必要になる場合があります。ただし、初期化が頻繁に必要で、パフォーマンスに本当に関心がある場合にのみ重要です。

1
t.g.