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)
const
を追加できますconst
と&
を追加できますそれらはすべてすでに言語の一部です。私は最初の3つのアイデアのみを書きました。多く他のアプローチがあると確信しています。
std
名前空間で定義された型を返す「コア」言語機能の例はすでにありました。 typeid
はstd::type_info
を返し、(おそらく点を伸ばす)sizeof
はstd::size_t
を返します。
前者の場合、このいわゆる「コア言語」機能を使用するには、すでに標準ヘッダーを含める必要があります。
現在、初期化子リストの場合、オブジェクトを生成するのにキーワードは不要であり、構文は状況依存の中括弧です。それ以外は、type_info
と同じです。個人的には、キーワードがないからといって「よりハック」になるとは思いません。おそらくもう少し驚くかもしれませんが、目的は、集計で既に許可されているのと同じブレース初期化構文を許可することだったことを思い出してください。
そのため、将来的には、この設計原則のさらなる向上が期待できます。
std
に配置されます。したがって:
std
」のライブラリタイプを使用する「コア言語」構文です。結局のところ、「コア言語」と標準ライブラリの間にC++の絶対的な分割がないということです。これらは標準の異なる章ですが、それぞれが他の章を参照しており、常にそうです。
C++ 11には別のアプローチがあります。それは、ラムダが、コンパイラによって生成される匿名タイプを持つオブジェクトを導入するということです。それらには名前がないため、名前空間にはまったく存在せず、std
にも存在しません。ただし、初期化リストを受け入れるコンストラクターを作成するときに型名を使用するため、初期化リストには適切なアプローチではありません。
C++標準委員会は、おそらく既存のコードを壊すリスクを高めるため、新しいキーワードを追加しないことを好むようです(レガシーコードは、そのキーワードを変数、クラス、またはその他の名前として使用できます)。
さらに、テンプレートコンテナとしてstd::initializer_list
を定義することは非常にエレガントな選択であるように思えます。キーワードである場合、基礎となる型にどのようにアクセスしますか。どのように繰り返しますか?多数の新しい演算子も必要になります。これにより、標準コンテナでできることと同じことを行うために、より多くの名前とキーワードを覚えておく必要があります。
std::initializer_list
を他のコンテナと同様に扱うことにより、これらのいずれかで機能する汎用コードを作成する機会が与えられます。
UPDATE:
次に、既存の組み合わせを使用する代わりに、なぜ新しいタイプを導入するのですか? (コメントから)
そもそも、他のすべてのコンテナには、コンパイラで生成されたコレクションには望ましくない要素を追加、削除、および実装するメソッドがあります。唯一の例外はstd::array<>
です。これは、固定サイズのCスタイルの配列をラップするため、妥当な唯一の候補のままです。
ただし、 Nicol Bolas がコメントで正しく指摘しているため、std::initializer_list
とその他すべての基本的な違いがあります。標準コンテナ(std::array<>
を含む)は、後者の値のセマンティクスを持ち、std::initializer_list
には参照セマンティクス。たとえば、std::initializer_list
をコピーしても、それに含まれる要素のコピーは発生しません。
さらに(再びニコルボーラスの厚意によります)、ブレースの初期化リスト用の特別なコンテナを使用すると、ユーザーが初期化を実行する方法でオーバーロードが可能になります。
これは新しいことではありません。たとえば、for (i : some_container)
は、some_container
クラスの 特定のメソッドまたはスタンドアロン関数の存在 に依存しています。 C#は.NETライブラリにさらに依存しています。実際、これは非常にエレガントなソリューションだと思います。言語仕様を複雑にすることなく、クラスをいくつかの言語構造と互換性を持たせることができるからです。
これは確かに新しいものではなく、多くの人が指摘しているように、このプラクティスはC++にあり、たとえばC#にもありました。
Andrei Alexandrescuはこれについて良い点を述べました:あなたはそれを想像上の「コア」名前空間の一部と考えるかもしれません、そしてそれはより理にかなっています。
したがって、実際には、_core::initializer_list
_、_core::size_t
_、core::begin()
、core::end()
などのようになります。これは、std
名前空間に中核となる言語構造が含まれているという不幸な偶然です。
標準ライブラリで完全に機能するだけでなく、標準ライブラリに含まれているからといって、コンパイラーが巧妙なトリックを実行できないわけではありません。
すべての場合に可能ではないかもしれませんが、非常によく言うかもしれません:この型はよく知られている、または単純な型で、_initializer_list
_を無視し、初期化された値がどうあるべきかのメモリイメージだけを持たせます。
言い換えると、_int i {5};
_はint i(5);
または_int i=5;
_またはさらに_intwrapper iw {5};
_と同等になります。ここでintwrapper
は、_initializer_list
_
これはコア言語の一部ではありません。ライブラリに完全に実装できるため、行operator new
およびoperator delete
。コンパイラをより複雑に構築するのにどのような利点がありますか?