범위 기반 for 루프를 사용할 때 반복기가 필요합니다.


84

현재 다음과 같이 범위 기반 루프 만 수행 할 수 있습니다.

for (auto& value : values)

그러나 때로는 참조 대신 값에 대한 반복자가 필요합니다 (어떤 이유로 든). 값을 비교하는 전체 벡터를 거치지 않고 방법이 있습니까?

답변:


77

이전 for루프를 다음과 같이 사용하십시오 .

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

이것으로 당신은 valueiterator뿐만 아니라 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되기 때문에 주어진 검색을 피 합니다.valueit


네, 이것이 제가하고있는 일입니다. 대신 원거리 기반 루프를 사용하는 솔루션이 있는지 궁금합니다.
小 太郎

4
이전 for 루프의 첫 번째 솔루션이 훨씬 낫다는 데 동의합니다. : P
小 太郎

@ 小 太郎 : 아니면 std::find값을 찾는 것이 필요한 경우 사용할 수 있습니다 ... 좋은 오래된 알고리즘은 여전히 ​​새로운 표준에 있습니다.
데이비드 로드리게스는 - dribeas

1
@David : 벡터에 중복이 있으면 어떨까요? valueit동기화 될 수 없다. value참고로 기억하십시오 .
Nawaz

9
@Nawaz : 마지막 문장을 오해 한 것 같아요. 나는 그가 알려진 물체를 찾기 위해 근거한 범위를 사용하고 있다고 생각했습니다. BTW 는 오버 헤드가 적을 수 있으므로 가능할 때마다 (코드에서 모두 사용) 선호 ++it합니다 it++.
David Rodríguez-dribeas 2011-08-05

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을 생각했고 사용량이 부풀어 오르는 것을 보았습니다 ... 그리고 그것이 함수에서 그의 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루프.


나는 그들이 대신 반복자를 사용하는 유사한 루프를 제공하기를 바랍니다. :(
小 太郎

1
당신이 얻는 것은 반복자가 아니라 가치가 있다는 것에 만족합니다 for. 반복자를 역 참조 auto
해야하는

2

이 작업을 수행하는 매우 간단한 방법이 std::vector있습니다. 프로세스 중에 벡터의 크기를 조정하는 경우에도 작동해야합니다 (승인 된 답변이이 경우를 고려하는지 여부는 확실하지 않습니다)

경우 b귀하의 벡터이다, 당신은 할 수 있습니다

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

iter필요한 반복자는 어디에 있습니까 ?

이것은 C ++ 벡터가 항상 연속적 이라는 사실을 이용합니다 .


2
이미 C ++ 벡터 연속이라는 사실을 악용하는 경우, 당신은뿐만 아니라 또한 제정신 구현이 단지 형식 정의는 사실 악용 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.