1

最近、イテレータが暗黙的にboolに変換されて、次のことができるようになればどうなるかを考えていました。

auto it = find(begin(x),end(x), 42);
if (it)  //not it!=x.end();
{
}

しかし、考えてみると、これはit「NULL」に設定する必要があることを意味するので、何かをしたい場合は直接使用できない(x.end()使用する必要がある)か、使用できることに気付きました。ただし、iterのサイズは大きくする必要があります(それが指しているものがそうであるかどうかを保存する .end()ため)。だから私の質問は:

  1. 私の例の構文は、現在のコードを壊すことなく、またイテレーターのサイズを増やすことなく達成できますか?
  2. 暗黙的にboolに変換すると、いくつかの問題が発生しますか?
4

4 に答える 4

3

イテレータはコンテナにアクセスする方法であるという前提で作業しています。それらはそれを可能にしますが、意図した操作に明らかに合わない多くのことも可能にします:

auto it = std::find(std::begin(x), std::next(std::begin(x),10), 42 );
    // Is 42 among the first 10 elements of 'x'?

auto it = std::find(std::istream_iterator<int>(std::cout),
                    std::istream_iterator<int>(), 42 );
    // Is 42 one of the numbers from standard input?

最初のケースでは、イテレータはコンテナを参照しますが、見つかった範囲itはコンテナ全体を囲んでいないため、に対してテストできませんend(x)。2 番目のケースでは、コンテナがまったくありません。

多くのコンテナーのイテレーターの効率的な実装はポインターのみを保持するため、他の状態ではイテレーターのサイズが大きくなることに注意してください。

any-typeまたはへの変換に関しては、多くの問題が発生しますが、C++11 では変換によって、または C++03 ではsafe-boolイディオムを使用してbool回避できます。explicit

おそらく、別の概念である範囲にもっと興味があるでしょう。範囲には複数のアプローチがあるため、正確なセマンティクスがどうあるべきかは明確ではありません。最初に思い浮かぶのは、Boost.Iterator と、最近読んだOn Iterationという Alexandrescu の記事です。

于 2012-10-05T16:10:07.010 に答える
2

おそらく、暗黙的な変換は必要ありませんが、反復がいつ行われるかを判断するために 2 つの別個のオブジェクトが必要になるのは、明らかに設計上の誤りです。ifまたは のせいではありませんfor(ただし、単一の反復子を使用すると、これらもより明確になります)。不可能ではないにしても、関数の分解と反復子のフィルタリングが非常に困難になるためです。

基本的に、STL イテレーターは、イテレーターというよりはスマート ポインターに近いものです。このようなポインターが適切な場合もありますが、イテレーターの代わりとしては適していません。

于 2012-10-05T17:04:39.967 に答える
2

単一の反復子で実行できることはほとんどありません。反復子のペアは、要素で構成されるシーケンスを定義します。最初の反復子は最初の要素を指し、2 番目の反復子は最後の要素の末尾の 1 つ後ろを指します。一般に、最初の反復子が 2 番目の反復子と一致するようにインクリメントされたときを知る方法はありません。アルゴリズムは、両方のイテレータを持ち、いつ作業が完了したかを知ることができるため、これを行います。例えば:

std::vector<int> vec;
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);

// copy the contents of the vector:
std::copy(somewhere, vec.begin(), vec.end());
// copy the first two elements of the vector:
std::copy(somewhere, vec.begin(), vec.begin() + 2);

copy の両方の呼び出しvec.begin()で、同じ反復子です。アルゴリズムは、いつ停止するかを指示する 2 番目の反復子を取得したため、さまざまなことを行います。

確かに、(Java のように) シーケンスの開始と終了の両方を含む別の種類のイテレーターを設計することは可能ですが、それは C++ イテレーターの設計方法ではありません。2 つの反復子を保持する「範囲」の概念を標準化することについての議論があります (新しい範囲ベースの for ループは、そのための第一歩です)。

于 2012-10-05T16:16:39.140 に答える
2

これが機能しない 2 つの理由:

まず、生のポインターを反復子として (通常は配列に) 使用することができます。

int data[] = { 50, 42, 37, 5 };
auto it = find(begin(data), end(data), 42);

次に、コンテナの実際の末尾を に渡す必要はありませんfind。たとえば、ピリオドの前の最初のスペース文字を見つけるには:

auto sentence = "Hello, world.";
auto it1 = find(begin(sentence), end(sentence), '.');
auto it2 = find(begin(sentence), it1, ' ');
于 2012-10-05T16:13:41.247 に答える