9

C++11 では、std::map<std::string, int>次のように a を初期化することは合法のようです。

std::map<std::string, int> myMap = {
     { "One",   1 },
     { "Two",   2 },
     { "Three", 3 }
};

直感的に、これは理にかなっています - 中括弧で囲まれたイニシャライザは、文字列のペアのリストであり、std::map<std::string, int>::value_type(std::pair<std::string, int>おそらくいくつかのconst修飾付き.

ただし、ここでタイピングがどのように機能するかを理解しているかどうかはわかりません。ここで変数宣言を削除し、中括弧で囲まれた初期化子だけを使用すると、コンパイラは、中括弧で囲まれたstd::initializer_list<std::pair<std::string, int>>ペアがstd::pairs を表していることを認識できないため、a を見ていることを認識できません。したがって、コンパイラはstd::map、ネストされた中括弧がペア用であることを認識するのに十分な型情報がコンストラクターから得られるまで、中括弧で囲まれた初期化子に型を割り当てる行為を何らかの形で延期しているように見えます。C++03 でこのようなことが起こったことを覚えていません。私の知る限り、式の型は文脈に依存することはありませんでした。

このコードが正しくコンパイルされ、コンパイラが初期化子リストに使用する型を決定できるようにする言語規則は何ですか? これが機能するのは本当に興味深いので、C++11仕様への特定の参照を含む回答を期待しています!

ありがとう!

4

2 に答える 2

9

式では

std::map<std::string, int> myMap = {
     { "One",   1 },
     { "Two",   2 },
     { "Three", 3 }
};

右側には、各要素がブレース初期化リストでもあるブレース初期化リストがあります。最初に起こることは、のイニシャライザ リスト コンストラクタstd::mapが考慮されることです。

map(initializer_list<value_type>,
    const Compare& = Compare(),
    const Allocator& = Allocator());

map<K, V>::value_typepair<const K, V>は、この場合は の typedef ですpair<const string, int>。内側の波括弧初期化リストは、構成要素の 2 つの型への参照を受け取るコンストラクターとmap::value_type、.std::pairstd::stringchar const *

したがって、のイニシャライザ リスト コンストラクタstd::mapは実行可能であり、ネストされたブレース初期化リストから構築を行うことができます。

関連する標準は、§13.3.1.7/1 [over.match.list]にあります。

非集合クラス型のオブジェクトがリスト初期化されている場合( 8.5.4 T)、オーバーロードの解決により、2 つのフェーズでコンストラクターが選択されます。 list は、単一の引数として初期化子リストで構成されます。 — 実行可能な初期化子リスト コンストラクターが見つからない場合、オーバーロードの解決が再度実行されます。この場合、候補関数はクラスのすべてのコンストラクターであり、引数リストは初期化子リストの要素で構成されます。
T
T

最初の箇条書きは、外側の波括弧初期化リストのinitializer_listコンストラクターmapが選択される原因となるものであり、2 番目の箇条書きは、内側の波括弧初期化リストの正しいpairコンストラクターの選択をもたらすものです。

于 2014-07-13T02:25:09.283 に答える
2

これはリストの初期化です。ルールは、標準の §8.5.4[dcl.init.list]/p3 にあります。

型 T のオブジェクトまたは参照のリスト初期化は、次のように定義されます。

  • 初期化子リストに要素がなく、T が既定のコンストラクターを持つクラス型である場合、オブジェクトは値で初期化されます。
  • それ以外の場合、T が集合体の場合、集合体の初期化が実行されます (8.5.1)。【例略】
  • それ以外の場合、 T が の特殊化であるstd::initializer_list<E>場合、initializer_listオブジェクトは以下で説明するように構築され、同じ型 (8.5) のクラスからオブジェクトを初期化するための規則に従ってオブジェクトを初期化するために使用されます。
  • それ以外の場合、T がクラス型の場合、コンストラクターが考慮されます。適用可能なコンストラクターが列挙され、オーバーロード解決 (13.3、13.3.1.7) によって最適なコンストラクターが選択されます。引数のいずれかを変換するために縮小変換 (以下を参照) が必要な場合、プログラムは不適切な形式です。
  • [ルールの例と残りの部分は省略]

これらの場合、オーバーロード解決はstd::initializer_listコンストラクターを優先することに注意してください (§13.3.1.7 [over.match.list])。

したがって、コンパイラは、非集約型、非std::initializer_listクラス型のオブジェクトを初期化するために使用される波括弧リストを検出すると、オーバーロードの解決を実行して適切なコンストラクターを選択し、実行可能なコンストラクターが存在する場合はそのコンストラクターを優先しinitializer_listます ( の場合と同様std::map)。

于 2014-07-13T02:25:33.473 に答える