範囲ベースのforループを使用する場合はイテレータが必要


84

現在、私はこれで範囲ベースのループしか実行できません:

for (auto& value : values)

しかし、参照ではなく、値へのイテレータが必要になる場合があります(何らかの理由で)。値を比較するベクトル全体を調べなくてもよい方法はありますか?

回答:


77

古いforループを次のように使用します。

for (auto it = values.begin(); it != values.end();  ++it )
{
       auto & value = *it;
       //...
}

これで、あなたはvalueイテレータと同様になりましたit。使いたいものは何でも使ってください。


編集:

私はこれをお勧めしませんが、範囲ベースのforループを使用したい場合(ええ、何らかの理由で:D)、これを行うことができます:

 auto it = std::begin(values); //std::begin is a free function in C++11
 for (auto& value : values)
 {
     //Use value or it - whatever you need!
     //...
     ++it; //at the end OR make sure you do this in each iteration
 }

とは常に同期しているvalueためvalue、このアプローチでは、指定された検索を回避できitます。


ええ、これは私がやってきたことです。代わりに、範囲ベースのループを使用したソリューションがあるかどうか疑問に思っていました
小太郎2011

4
古いforループを使用した最初のソリューションの方がはるかに優れていることに同意します:P
小太郎2011

@小太郎:または、std::find必要なのが値を見つけることである場合に使用できます...古き良きアルゴリズムはまだ新しい標準にあります。
デビッド・ロドリゲス-ドリビア2011

1
@David:ベクターに重複がある場合はどうなりますか?valueそして、it同期していなくてもよいです。覚えておいvalueてください。
nawaz 2011

9
@Nawaz:最後の文を誤解したと思います。私は彼が既知のオブジェクトを見つけるためにに基づいた範囲を使用していると思いました。ところで、好み++itit++それが低いオーバーヘッドを持っている可能性があるとして、可能な限り(あなたのコード内の両方の用途)。
デビッド・ロドリゲス-ドリビア2011

15

これは、独自の変数にエイリアスすることで非表示のイテレータを公開できるようにするプロキシラッパークラスです。

#include <memory>
#include <iterator>

/*  Only provides the bare minimum to support range-based for loops.
    Since the internal iterator of a range-based for is inaccessible,
    there is no point in more functionality here. */
template< typename iter >
struct range_iterator_reference_wrapper
    : std::reference_wrapper< iter > {
    iter &operator++() { return ++ this->get(); }
    decltype( * std::declval< iter >() ) operator*() { return * this->get(); }
    range_iterator_reference_wrapper( iter &in )
        : std::reference_wrapper< iter >( in ) {}
    friend bool operator!= ( range_iterator_reference_wrapper const &l,
                             range_iterator_reference_wrapper const &r )
        { return l.get() != r.get(); }
};

namespace unpolluted {
    /*  Cannot call unqualified free functions begin() and end() from 
        within a class with members begin() and end() without this hack. */
    template< typename u >
    auto b( u &c ) -> decltype( begin( c ) ) { return begin( c ); }
    template< typename u >
    auto e( u &c ) -> decltype( end( c ) ) { return end( c ); }
}

template< typename iter >
struct range_proxy {
    range_proxy( iter &in_first, iter in_last )
        : first( in_first ), last( in_last ) {}

    template< typename T >
    range_proxy( iter &out_first, T &in_container )
        : first( out_first ),
        last( unpolluted::e( in_container ) ) {
        out_first = unpolluted::b( in_container );
    }

    range_iterator_reference_wrapper< iter > begin() const
        { return first; }
    range_iterator_reference_wrapper< iter > end()
        { return last; }

    iter &first;
    iter last;
};

template< typename iter >
range_proxy< iter > visible_range( iter &in_first, iter in_last )
    { return range_proxy< iter >( in_first, in_last ); }

template< typename iter, typename container >
range_proxy< iter > visible_range( iter &first, container &in_container )
    { return range_proxy< iter >( first, in_container ); }

使用法:

#include <vector>
#include <iostream>
std::vector< int > values{ 1, 3, 9 };

int main() {
    // Either provide one iterator to see it through the whole container...
    std::vector< int >::iterator i;
    for ( auto &value : visible_range( i, values ) )
        std::cout << "# " << i - values.begin() << " = " << ++ value << '\n';

    // ... or two iterators to see the first incremented up to the second.
    auto j = values.begin(), end = values.end();
    for ( auto &value : visible_range( j, end ) )
        std::cout << "# " << j - values.begin() << " = " << ++ value << '\n';
}

13

私はこれを試してみて、解決策を見つけました。

使用法:

for(auto i : ForIterator(some_list)) {
    // i is the iterator, which was returned by some_list.begin()
    // might be useful for whatever reason
}

実装はそれほど難しくありませんでした。

template <typename T> struct Iterator {
    T& list;
    typedef decltype(list.begin()) I;

    struct InnerIterator {
        I i;
        InnerIterator(I i) : i(i) {}
        I operator * () { return i; }
        I operator ++ () { return ++i; }
        bool operator != (const InnerIterator& o) { return i != o.i; }
    };

    Iterator(T& list) : list(list) {}
    InnerIterator begin() { return InnerIterator(list.begin()); }
    InnerIterator end() { return InnerIterator(list.end()); }
};
template <typename T> Iterator<T> ForIterator(T& list) {
    return Iterator<T>(list);
}

ああ、そうですね。コンパイラーがコンストラクターからTを取得できるとは言えませんでした...それでdecltypeを考えて、usage-bloatを見ました...そして関数からTを取得できるとは思いませんでした...関数テンプレート、ありがとう。それは正しいですか、私は今それをどのようにしていますか?
ペイロード

2
ええ、それはよさそうだ。FWIWがありboost::counting_iteratorますが、これはまさにそれを実行し、便利にでラップされているboost::counting_rangeので、次のように書くことができますfor(auto it : boost::counting_range(r.begin(), r.end()))。:)
Xeo 2013

1
operator++()InnerIterator、そうでなければ非常に素晴らしくて有用なを返す必要があると思います。
Ben Voigt

2

範囲ベースの forループはforeach、配列要素の簡単な反復を可能にするJavaのc ++対応物として作成されます。これは、イテレータなどの複雑な構造の使用を削除して、単純にすることを目的としています。iteratorナワズが言ったように、私はあなたが欲しいです、あなたは通常のforループを使わなければならないでしょう。


代わりにイテレータを使用した同様のループを提供してほしいのですが:(
小太郎2011

1
私にとって、範囲ベースforはシンタックスシュガーであり、入力量を減らすことであるため、イテレータではなく値が得られることを嬉しく思います。イテレータを逆参照する必要があると、特に一緒に使用した場合にエラーが発生しやすくなりますauto
TeaOverflow 2012年

2

に対してこれを行う非常に簡単な方法があります。これは、std::vectorプロセス中にベクトルのサイズを変更する場合にも機能するはずです(受け入れられた回答がこのケースを考慮しているかどうかはわかりません)

bあなたのベクトルなら、あなたはただすることができます

for(auto &i:b){
    auto iter = b.begin() + (&i-&*(b.begin()));
}

iter必要なイテレータはどこにありますか。

これは、C ++ベクトルが常に連続しているという事実を利用しています。


2
あなたは既にC ++ベクトルが連続しているという事実を利用している場合は、あなたにもまた、まともな実装はただのtypedefという事実悪用vector<T>::iteratorT*チェックしていること:static_assert()、そしてちょうど使用をT* iter = &i;
cmaster -モニカ復活

1

非常に汚いことをしましょう...私は知っています、0x70hはスタック使用法、コンパイラバージョン、...で変更されています。コンパイラによって公開されるはずですが、そうではありません:-(

char* uRBP = 0; __asm { mov uRBP, rbp }
Iterator** __pBegin = (Iterator**)(uRBP+0x70);
for (auto& oEntry : *this) {
    if (oEntry == *pVal) return (*__pBegin)->iPos;
}

1
私には言葉がありません、これは非常に多くのレベルで間違っています、私はそれを批評し始める場所さえ知りません。
swineone
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.