2010-07-06 5 views
10

for_each()을 사용하여 일부를 컨테이너의 일부로 Function (으)로 전화 할 수 있습니까?for_each에서 함수와 술어를 결합하는 방법은 무엇입니까?

나는

for(i in shapes) 
    if(i.color == 1) 
     displayShape(i); 

을 할 수있는 for_each_if()을 만들었으며

for_each_if(shapes.begin(), shapes.end(), 
         bind2nd(ptr_fun(colorEquals), 0), 
         ptr_fun(displayShape)); 

bool colorEquals(Shape& s, int color) { 
    return s.color == color; 
} 

그러나, 내가 STL과 같은 알고리즘을 immitating 것은 내가 일을해야 일이 아니다 느낌처럼 통화가 보인다.

  1. 이렇게하려면 기존 STL 키워드 만 사용하는 방법이 있습니까?

    내가

  2. 은 *가 더 복잡한 경우, 펑의 이름은 무엇 펑터에 대한 오해의 소지가 될 것 때문에 하지

    for_each(shapes.begin(), shapes.end(), 
            bind2nd(ptr_fun(display_shape_if_color_equals), 0)); 
    

    을하고 싶지 않았다 거기 (colorEquals과 같은) 구조체의 멤버에 액세스하는 방법은 for_each과 같은 함수를 만들 필요없이? *

답변

1

if 조건을 에뮬레이트하는 Functor가 필요한 경우 if_each와 함께 for_each를 사용하십시오. 어떻게 든 바인더가 unary_function되는 반환과 혼란을 얻을 수 있지만 어쨌든 boost::bind 꽤 잘 보이는

#include <algorithm> 
#include <vector> 
#include <functional> 
#include <iostream> 
#include <boost/bind.hpp> 

using namespace std; 

struct incr { 
    typedef void result_type; 
    void operator()(int& i) { ++i; } 
}; 

struct is_odd { 
    typedef bool return_type; 
    bool operator() (const int& value) {return (value%2)==1; } 
}; 


template<class Fun, class Cond> 
struct if_fun { 
    typedef void result_type; 
    void operator()(Fun fun, Cond cond, int& i) { 
    if(cond(i)) fun(i); 
    } 
}; 


int main() { 
    vector<int> vec; 
    for(int i = 0; i < 10; ++i) vec.push_back(i); 

    for_each(vec.begin(), vec.end(), boost::bind(if_fun<incr, is_odd>(), incr(), is_odd(), _1)); 
    for(vector<int>::const_iterator it = vec.begin(); it != vec.end(); ++it) 
    cout << *it << " "; 
} 

불행하게도 내 템플릿 해커는 bind1st와 bind2nd 이것을 관리 할 충분하지 않습니다. 내 예제는 Func이 if_fun으로 전달 된 것을 허용하지 않기 때문에 완벽하지는 않습니다. 누군가가 더 많은 결함을 지적 할 수 있습니다. 제안을 환영합니다.

+0

차가움. 이제는 for_each()를 호출 할 때 템플릿 매개 변수를 줄일 수 있도록'if_fun' 객체를 인스턴스화하는 도우미 함수를 추가 할 수 있다고 가정합니다 ... –

+0

boost :: bind는 일반 함수와 마찬가지로 잘 작동하므로 클래스 기반 Functors는 실제로 필요하지 않습니다 – bradgonesurfing

+0

이 솔루션은 직관적 인 혼란의 지옥입니다. 부스트 어댑터와 범위가 여기에서 사용하고자하는 것입니다. – newhouse

8

STL과 유사한 알고리즘을 모방하는 것은 정확히 수행해야하는 작업입니다. 그것이 바로 STL에있는 이유입니다.

특히 실제 함수를 만들고 바인딩하는 대신에 함수기를 사용할 수 있습니다. 이것은 훨씬 더 깔끔합니다.

template<typename Iterator, typename Pred, typename Operation> void 
for_each_if(Iterator begin, Iterator end, Pred p, Operation op) { 
    for(; begin != end; begin++) { 
     if (p(*begin)) { 
      op(*begin); 
     } 
    } 
} 
struct colorequals { 
    colorequals(int newcol) : color(newcol) {} 
    int color; 
    bool operator()(Shape& s) { return s.color == color; } 
}; 
struct displayshape { 
    void operator()(Shape& s) { // display the shape } 
}; 
for_each_if(shapes.begin(), shapes.end(), colorequals(0), displayshape()); 

이것은 일반적으로 이동하는 관용적 인 방법으로 간주됩니다.

+0

필자는 ~ 10 개의 C++ 컴파일러를 사용해야하는데, 일부는 90 년대 후반까지 거슬러 올라갑니다. STL 구현은 매우 다양하여 STL의 S는 '표준'을 의미하지 않습니다. 그렇기 때문에 STL 기능을 모르는 채로 피하는 경향이 있습니다. for_each_if()가 문제를 해결하는 방법이라면 STL에 이미 있어야한다고 생각합니다. 그렇지 않습니까? (나는 이미 remove_if, find_if, count_if가 있음을 의미합니다). –

+1

@Grim : 사람들은 일반적으로 for_each의 functor에 if를 넣습니다. 그러한 for_each_if 구조는 필요 없습니다. – Puppy

4

부스트 범위 어댑터를 사용하는 것이 훨씬 깔끔합니다.

using boost::adaptor::filtered; 
using boost::bind; 

class Shape { 
    int color() const; 
}; 

void displayShape(const Shape & c); 

bool test_color(const Shape & s, int color){ 
    return s.color() == color; 
} 

boost::for_each 
    (vec | filtered(bind(&test_color, _1, 1) 
    , bind(&displayShape, _1) 
    ) 

참고 범위와 범위 어댑터에 찬성 추상적 멀리 반복자에 새로운 범위 라이브러리의 사용 라이브러리는 작업의 파이프 라인을 구성합니다.

모든 표준 stl 반복기 기반 알고리즘은 범위 기반 알고리즘에 이식 된 입니다.

typedef boost::unordered_map<int, std::string> Map; 
Map map; 
... 
using boost::adaptor::map_keys; 
using boost::bind 
using boost::ref 
using boost::adaptor::filtered; 

bool gt(int a, int b) 
{ return a > b }; 

std::string const & get(const Map & map, int const & a) 
{ return map[a] } 

// print all items from map whose key > 5 
BOOST_FOREACH 
    (std::string const & s 
    , map 
     | map_keys 
     | filtered(bind(&gt, _1, 5)) 
     | transformed(bind(&get, ref(map), _1)) 
    ) 
    { 
     cout << s; 
    } 

읽기 Range AdaptorsRange Algorithm을 상상해보십시오.

+0

자동 url-> a href 변환은 길이 때문에 아마도 알고리즘 하나를 생략했습니다. –

관련 문제