100

std::initializer_listコア言語が組み込まれていないのはなぜですか?

これは C++11 の非常に重要な機能のように思えますが、独自の予約キーワード (または類似のもの) はありません。

代わりに、コンパイラによって処理される新しい波括弧初期化リスト構文からの特別な暗黙的なマッピングinitializer_listを持つ、標準ライブラリからの単なるテンプレート クラスです。 {...}

一見すると、このソリューションは非常にハックです。

これは、C++ 言語への新しい追加が実装される方法ですか?コア言語ではなく、いくつかのテンプレート クラスの暗黙の役割によってですか?


次の例を検討してください。

   widget<int> w = {1,2,3}; //this is how we want to use a class

新しいクラスが選ばれた理由:

   widget( std::initializer_list<T> init )

これらのアイデアにたものを使用する代わりに:

   widget( T[] init, int length )  // (1)
   widget( T... init )             // (2)
   widget( std::vector<T> init )   // (3)
  1. const古典的な配列、おそらくあちこちに追加できます
  2. 言語には 3 つのドットが既に存在します (var-args、現在は variadic テンプレート)。構文を再利用してみませんか (そして組み込みのように感じさせます)
  3. 既存のコンテナだけで、追加constして&

それらはすべて、すでに言語の一部です。最初の 3 つのアイデアだけを書きましたが、他にも多くのアプローチがあると確信しています。

4

6 に答える 6

48

std名前空間で定義された型を返す「コア」言語機能の例は既にありました。typeidを返しstd::type_info、(おそらくポイントをストレッチして) をsizeof返しますstd::size_t

前者の場合、このいわゆる「コア言語」機能を使用するには、すでに標準ヘッダーを含める必要があります。

ここで、初期化子リストの場合、オブジェクトを生成するためにキーワードが必要ない場合があります。構文はコンテキスト依存の中括弧です。それ以外は と同じtype_infoです。個人的には、キーワードがなくても「ハッキー」になるとは思いません。もう少し驚くべきことかもしれませんが、その目的は、集約に対して既に許可されているのと同じ波括弧付き初期化子構文を許可することであったことを思い出してください。

そうです、おそらく将来的にはこの設計原則がさらに増えることを期待できます。

  • 新しいキーワードなしで新しい機能を導入できる機会がさらに発生した場合、委員会はそれらを取り上げます。
  • 新しい機能が複雑な型を必要とする場合、それらの型はstdビルトインとしてではなくに配置されます。

したがって:

  • 新しい機能が複雑な型を必要とし、新しいキーワードなしで導入できる場合、ここにあるものを取得できます。これは、新しいキーワードのない「コア言語」構文であり、std.

結局のところ、C++ には「コア言語」と標準ライブラリの間に絶対的な区分がないということです。それらは標準の異なる章ですが、それぞれが他の章を参照しており、常にそうでした。

C++11 には別のアプローチがあります。これは、コンパイラによって生成された匿名型を持つオブジェクトをラムダが導入するというものです。それらには名前がないため、名前空間にはまったく含まれていませんstd。ただし、これは初期化子リストに適したアプローチではありません。型名を受け入れるコンストラクターを作成するときに型名を使用するためです。

于 2013-03-04T10:30:34.927 に答える
42

C ++標準委員会は、おそらく既存のコードを壊すリスクを高めるため、新しいキーワードを追加しないことを好むようです(レガシーコードはそのキーワードを変数やクラスなどの名前として使用できます)。

さらに、テンプレート化されたコンテナとして定義することstd::initializer_listは非常に洗練された選択であるように思われます。それがキーワードである場合、その基になるタイプにどのようにアクセスしますか?それをどのように繰り返しますか?たくさんの新しい演算子も必要になります。これにより、標準のコンテナーで実行できるのと同じことを実行するために、より多くの名前とキーワードを覚えておく必要があります。

を他のコンテナと同じように扱うstd::initializer_listと、それらのいずれかで機能するジェネリックコードを作成する機会が得られます。

アップデート:

では、なぜ既存の組み合わせを使用するのではなく、新しいタイプを導入するのでしょうか。(コメントから)

まず、他のすべてのコンテナーには、要素を追加、削除、および配置するためのメソッドがありますが、これはコンパイラーによって生成されたコレクションには望ましくありません。唯一の例外はstd::array<>、です。これは、固定サイズのCスタイルの配列をラップするため、唯一の妥当な候補であり続けます。

ただし、Nicol Bolasがコメントで正しく指摘しているように、他のstd::initializer_listすべての標準コンテナ(を含むstd::array<>)とのもう1つの基本的な違いは、後者のコンテナには値のセマンティクスstd::initializer_listがあり、参照のセマンティクスがあることです。たとえば、をコピーstd::initializer_listしても、そこに含まれる要素のコピーは作成されません。

さらに(もう一度、Nicol Bolasの好意により)、中括弧の初期化リスト用の特別なコンテナーがあると、ユーザーが初期化を実行する方法でオーバーロードが可能になります。

于 2013-03-04T10:02:54.050 に答える
6

これは新しいことではありません。たとえば、クラス内の特定のメソッドまたはスタンドアロン関数の存在にfor (i : some_container)依存します。C#は、.NETライブラリにさらに依存しています。実際、言語仕様を複雑にすることなくクラスをいくつかの言語構造と互換性を持たせることができるので、これは非常に洗練されたソリューションだと思います。some_container

于 2013-03-04T10:02:37.373 に答える
4

これは確かに新しいことではなく、何人が指摘したかというと、この慣行は C++ にあり、たとえば C# にもあります。

ただし、Andrei Alexandrescu はこれについて良い点を述べています。架空の「コア」名前空間の一部と考えると、より理にかなっています。

つまり、実際には次のようなものです: core::initializer_listcore::size_tcore::begin()などcore::end()stdこれは、名前空間の内部にいくつかのコア言語構造があるという不幸な偶然です。

于 2013-03-07T03:53:14.400 に答える
2

標準ライブラリで完全に機能するだけではありません。標準ライブラリに含まれているからといって、コンパイラが巧妙なトリックを実行できないわけではありません。

すべての場合に可能であるとは限りませんが、このタイプはよく知られている、または単純なタイプであるため、を無視しinitializer_listて、初期化された値がどうあるべきかについてのメモリイメージを持たせることができます。

言い換えればint i {5};、と同等である可能性があります。int i(5);または、int i=5;またはでさえありますintwrapper iw {5};intwrapperinitializer_list

于 2013-03-08T16:48:38.927 に答える
1

これはコア言語の一部ではありません。行operator newoperator delete. コンパイラの組み込みをより複雑にすることには、どのような利点がありますか?

于 2013-03-04T13:35:28.590 に答える