2011-04-11 1 views
2

STL 컬렉션을 반복하는 관용구는 다음과 같습니다.왜 항상 std :: for_each에서 반복자를 지정해야합니까?

int a[] = { 1,2,3 }; 
std::vector<int> v(a, a+3); 

std::for_each(a.begin(), a.end(), some_function); 

첫 번째이자 마지막 반복자를 지정하면 컬렉션의 특정 범위에서만 작업하려는 경우 유용합니다. 좀 더 창조적 인 일을해라.하지만 대부분의 경우, 나는 우리가 실제로 전체 컬렉션 작업을 원한다고 생각한다. 그래서 사람들이 왜 그런 상황에서 반복자를 지정해야하는지 궁금해합니다. (항상 같기 때문에) 다음 라인을 따라 편의 함수를 사용하지 마십시오 :

namespace easy 
{ 
    template <class T, class F> 
    F for_each(T& collection, F function) 
    { 
    std::for_each(collection.begin(), collection.end(), function); 
    return function; 
    } 
} 

(물론, 이 은 일을하는 관용적 인 방법 인 일 가능성이 있으며, 나는 결코 눈치 채지 못했습니다! 저는 C++에 익숙하지 않습니다.)

+1

대부분의 STL 과중 프로젝트에는 'for_each'와 같은 기능을 가진 "알고리즘 헬퍼"헤더가 있다는 것을 짐작할 수 있습니다. 필자가 일반적으로 사용하는 함수는 포인터의 범위와 컨테이너에 사용되는'indirect_for_each' 및'indirect_for_all'과 함께 함수가 수행하는'for_all'을 가지고 있습니다. –

답변

5

나는 STL을 위해 전적으로가 GA 다. 하지만 실제로는 for_each을 사용하여 리콜 할 수 없습니다.

관용구는이 사용자의 편의 기능과 유사

for (auto elem : coll) 

이를 줄이기 위해 설탕을 도입,하지만 std::beginstd::end 무료 (비회원)를 사용하여 C++ (11)

for (container::iterator it = coll.begin(); it != coll.end(); ++ it) 

표준 컨테이너가 아닌 객체와의 호환성을 허용하는 함수.

또한 GCC 에서처럼 아직까지 살펴 보지 못했습니다. 프로그래머가 범위의 요소에 액세스하고 반복기를 억세스하지 못하게하는 것 같습니다.


컨테이너를 사용하여 해당 범위 전체를 참조하는 경우 하위 범위를 허용하는 유연성을 유지하는 것이 좋습니다. 또 다른 해결책은 쌍의 반복자에 대한 관용구, { begin, end }을 도입하는 것입니다. 이 논쟁이 있었고, 전

begin(make_pair(begin_, end_)) // == begin_, 
end(make_pair(begin_, end_)) // == end_, 
for (auto elem : make_pair(begin_, end_)) // iterates over [ begin_, end) 

하지만 pair과 같은 표준을 읽는시

이 기능이 부족되도록 기능을 포함하는 C에게 ++ (11)를 예상했다.

당신은 만들 수 있습니다 자신의 등 pair하지만, 얻을 수있는 유연한 범위 기반 for :

template< typename iter > 
struct range_type { 
    iter first, last; 

    // use friends because Standard specifies these should be found by ADL: 
    friend iter begin(range_type const &r) { return r.first; } 
    friend iter end(range_type const &r) { return r.last; } 
}; 

template< typename iter > 
range_type<iter> range(iter first, iter last) 
    { return range_type<iter>{ first, last }; } 

// usage: 
for (auto elem : range(begin_, end_)) // iterates over [ begin_, end) 
+0

고마워요 (특히 다음 C++에 관한 내용입니다!). –

+0

@Jonathan : 자세한 내용으로 업데이트 됨 – Potatoswatter

1

내가 그런 말을해야 할 것하지만 잘못된 것은, 당신이 제안하는 것과도 없다 가능 Boost.ForEach 현재의 C++ 세계에있는 것들이 "관용적"인 것과 거의 비슷합니다.

사용과 같이 보이는이 방법의 장점 :

BOOST_FOREACH(value_type i, collection) { 
    function(i); 
} 

당신은 또한 명시 적 기능 매핑에 엄격하게 구속하여 작업을 인라인하지 수 있다는 것입니다.

1

이유는 STL의 디자이너는 이론적 인 측면에서 온 것입니다. Comp.Sci에서 범위는 컨테이너보다 더 기본적인 개념입니다. 실제로 컨테이너는 훨씬 더 보편적입니다.STL은 1996-1998 년에 심각한 시간 압력을 받고 추가되었으며 공격적으로 리팩토링되지 않았습니다.

std::for_each의 세 번째 인수와 비슷한 문제가 나타납니다. 이론 상으로는 람다가 존재합니다. C++ 98에서는 그렇지 않습니다. 따라서 펑 터를 라인 밖으로 정의하거나, 바인더와 컴포 지터와 함께 자세한 구문을 사용하거나, 상태 비 저장 포인터를 사용해야했습니다.

개인적으로 모든 STL 알고리즘은 한 쌍의 반복자가 아니라 범위 (단일 객체)를 가져야한다고 생각합니다. 후자를 범위 내에서 감싸는 것은 간단합니다. 이제 ostream_iterator는 오히려 임의의 최종 객체를 정의해야합니다.

2

가 대신 컬렉션의 시작과 끝 반복자를 지정하는 것은 참으로 지루하고 오류 경향이있다 (예를 들어, 귀하의 예제 코드는 잘못 .begin().end() 대신 va에 전화를 시도했다). 그것이 Boost Range가 발명 된 이유입니다. 또한 자신의 유용성과 일반성을 곱 알고리즘으로 구성 될 수 범위 어댑터의 개념을 도입

int a[] = { 1,2,3 }; 
boost::for_each(a, some_function); 

: 그것으로 당신과 같은 코드를 작성 할 수 있습니다.

[추측] STL이 범위 대신 반복자를 사용하는 이유는 알고리즘을 구성하고 이러한 알고리즘에 대한 최소 요구 사항을 찾아 이러한 요구 사항의 측면에서 표현한다는 관점에서 생각한 것입니다. 알고리즘을 사용하는 자연스러운 일은 실제로는 값의 범위 임에도 불구하고 알고리즘에서는 반복자가 작업을 수행해야합니다. 다른 답변에서 언급했듯이 STL은 심각한 시간 압박을받으며 이러한 문제는 해결되지 않았습니다. 운좋게도 현대인들은 Boost.Range를 가지고 있으므로 범위 기반 알고리즘을 사용할 수 있습니다.