web-dev-qa-db-ja.com

std :: initializer_listが組み込み言語ではないのはなぜですか?

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

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

代わりに、initializer_listそれはjust特別な暗黙のmappingを持つ標準ライブラリのテンプレートクラスですbraced-init-list{...}コンパイラーによって処理される構文。

最初に考えたとき、この解決策はかなりhackyです。

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


これらの例を考慮してください:

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

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

   widget( std::initializer_list<T> init )

これらのアイデアのいずれかにsimilarを使用する代わりに:

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

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

92
emesx

std名前空間で定義された型を返す「コア」言語機能の例はすでにありました。 typeidstd::type_infoを返し、(おそらく点を伸ばす)sizeofstd::size_tを返します。

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

現在、初期化子リストの場合、オブジェクトを生成するのにキーワードは不要であり、構文は状況依存の中括弧です。それ以外は、type_infoと同じです。個人的には、キーワードがないからといって「よりハック」になるとは思いません。おそらくもう少し驚くかもしれませんが、目的は、集計で既に許可されているのと同じブレース初期化構文を許可することだったことを思い出してください。

そのため、将来的には、この設計原則のさらなる向上が期待できます。

  • 新しいキーワードを使用せずに新しい機能を導入することが可能な場合は、委員会がそれらを採用します。
  • 新しい機能が複雑なタイプを必要とする場合、それらのタイプはビルトインとしてではなく、stdに配置されます。

したがって:

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

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

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

47
Steve Jessop

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

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

std::initializer_listを他のコンテナと同様に扱うことにより、これらのいずれかで機能する汎用コードを作成する機会が与えられます。

UPDATE:

次に、既存の組み合わせを使用する代わりに、なぜ新しいタイプを導入するのですか? (コメントから)

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

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

さらに(再びニコルボーラスの厚意によります)、ブレースの初期化リスト用の特別なコンテナを使用すると、ユーザーが初期化を実行する方法でオーバーロードが可能になります。

42
Andy Prowl

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

6
Spook

これは確かに新しいものではなく、多くの人が指摘しているように、このプラクティスはC++にあり、たとえばC#にもありました。

Andrei Alexandrescuはこれについて良い点を述べました:あなたはそれを想像上の「コア」名前空間の一部と考えるかもしれません、そしてそれはより理にかなっています。

したがって、実際には、_core::initializer_list_、_core::size_t_、core::begin()core::end()などのようになります。これは、std名前空間に中核となる言語構造が含まれているという不幸な偶然です。

4
Artem Tokmakov

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

すべての場合に可能ではないかもしれませんが、非常によく言うかもしれません:この型はよく知られている、または単純な型で、_initializer_list_を無視し、初期化された値がどうあるべきかのメモリイメージだけを持たせます。

言い換えると、_int i {5};_はint i(5);または_int i=5;_またはさらに_intwrapper iw {5};_と同等になります。ここでintwrapperは、_initializer_list_

2
Paul de Vrieze

これはコア言語の一部ではありません。ライブラリに完全に実装できるため、行operator newおよびoperator delete。コンパイラをより複雑に構築するのにどのような利点がありますか?

1
Pete Becker