2013-07-22 9 views
29

listというstd::initializer_listを受け取り、listの要素にランダムアクセスする必要がある関数を記述しているとします。 list.begin()[i]の代わりにlist[i]と書くと便利です。だから、なぜstd::initializer_listoperator[]の定義を提供しないのですか?`std :: initializer_list`が添字演算子を提供しないのはなぜですか?

operator[]を返すconst T&が明確に定義されていないケースは考えられません。 std::initializer_list<T>::iteratorには、明らかにランダムアクセスイテレータであるconst T*にエイリアスが付けられているため、効率は問題ではないようです。

+1

私の推測では、その主要な使用事例は、順次処理されるリストであるためです。 – PlasmaHH

+2

一般的な使用例は、メモリブロックを割り当て、 'allocator.construct(p、v)'を使ってブロック内の要素を構築するコンストラクタです。リストはまだ順番に処理されていますが、外側のfor-loopはすでに 'operator []'構文に役立つカウンタを持っています。 –

+0

@ void-pointerこれらの状況で通常*コピー*しませんか?そうすれば、ループは必要なくなり、とにかく明示的なループを避けることができます。しかし、問題はまだ有効です。 –

答えて

9

は、C++プログラミング言語、第4版のセクション17.3.4.2でビャーネ・ストロヴストルップ(P 497)によると:

残念ながら、initializer_listは添字を提供していません。

これ以上の理由はありません。

私の推測では、それはこれらの理由の一つだということです。

  1. initializer_listクラスが配列で実装されていて、安全なアクセスを提供するために、境界チェックをしなければならないと思いますので、それは省略、または
  2. です、それはより簡単にinitializer_listsであるため、STDアルゴリズム反復パラダイム、または
  3. と一致するようにそのインターフェイスが提供された場合に危険な状態で使用、または
  4. することができ、その性質上、アドホックで、によるエラーのためのより多くの部屋があります直接アドレスする

2と4の弱い種類の弱い。私のお金は1です。

+1

今日はBjarneの本を読んで、理由を探していた... – lpapp

2

特定のインデックスに対するランダムな直接アクセスの必要性が合理的なシナリオであるので、それは実際には少し迷惑で、std :: initializer_listに対して角括弧の演算子を持たないのです。

しかし、この能力は、いくつかの簡単なコードを追加することができます。今、私たちは、私たちがない限り、おそらく世界的なC++メソッドの良い名前ではありません_という名前の新しいグローバル関数(アンダースコア)を持っている

// the class _init_list_with_square_brackets provides [] for initializer_list 
template<class T> 
struct _init_list_with_square_brackets { 
    const std::initializer_list<T>& list; 
    _init_list_with_square_brackets(const std::initializer_list<T>& _list): list(_list) {} 
    T operator[](unsigned int index) { 
     return *(list.begin() + index); 
    } 
}; 

// a function, with the short name _ (underscore) for creating 
// the _init_list_with_square_brackets out of a "regular" std::initializer_list 
template<class T> 
_init_list_with_square_brackets<T> _(const std::initializer_list<T>& list) { 
    return _init_list_with_square_brackets<T>(list); 
} 

独自のネームスペースを持つC++用の "嫌なような"ユーティリティlibを作成して、他のすべての有用な用途のために_関数をオーバーロードします。

新しい_機能は次のように使用できるようになりました。

void f(std::initializer_list<int> list) { 
    cout << _(list)[2]; // subscript-like syntax for std::initializer_list! 
} 

int main() { 
    f({1,2,3}); // prints: 3 
    cout << _({1,2,3})[2]; // works also, prints: 3 
    return 0; 
} 

それはあなたがSTDの多くの項目上で実行する場合上記の解決策は、パフォーマンスの面で良い掘り出し物はないことに留意すべきです。 :上記の推奨型の一時オブジェクトとしてのinitializer_listは、_init_list_with_square_bracketsが繰り返し作成されます。これはもちろん、なぜこれが規格自体によって提供されなかったのだろうかという疑問を提起する。

+0

それはいいですね。代わりに、@ Yakkの質問に対するハイジャックのコメントは "auto mylist = list.begin()"で、次にmylist [n]が動作します。 –

+4

コード内に構文があるとすぐに "wtf"になります。私は、 '_'は実際にはidであり、関数をあまり意味しないということは無知になります。 rlyのように、 "wtf"。私はおそらく最終的にそれを理解するでしょう( "_"という名前のIDのために働く "定義に行く")が、書いたコーダーの家族の私の強烈な、速く、繰り返しの言及を軽減するために何もしませんそれ。私のアドバイスは 'list.begin()[i]'と一緒に行っています。私はそれがクールなトリック、言語賢明だからdownvoteに申し訳ありませんが、実際にはそれは逆行するでしょう。 – bolov

+0

私はあなたが実際にコピーの代わりに 'cons T&'を返そうと思っています。 – MikeMB

関連する問題