범위 기반 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 : 벡터에 중복이 있으면 어떨까요? value및 it동기화 될 수 없다. 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>::iterator을 T*점검하십시오에 있음 : 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.