2010-07-06 19 views
10

Làm cách nào bạn có thể gọi số Function trên một số một phần của vùng chứa, sử dụng for_each()?Làm thế nào để kết hợp một hàm và một vị từ trong for_each?

tôi đã tạo ra một for_each_if() để làm một

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

và cuộc gọi trông giống như

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; 
} 

Tuy nhiên, tôi cảm thấy immitating thuật toán STL-như không phải là một cái gì đó mà tôi nên làm.

  1. Có cách nào để chỉ sử dụng từ khóa STL hiện có để tạo ra điều này không?

    tôi đã làm không muốn làm một

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

    bởi vì, trong một trường hợp phức tạp hơn, tên functor sẽ gây hiểu lầm đối với những gì các functor với

  2. * Có cách truy cập thành viên của cấu trúc (như colorEquals) đối với các chức năng như for_each mà không cần phải tạo chức năng? *

Trả lời

1

Để sử dụng for_each thông thường nếu bạn cần một Functor mô phỏng điều kiện if.

#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 << " "; 
} 

Thật không may mẫu hackery của tôi là không đủ tốt để quản lý này với bind1st và bind2nd vì nó bằng cách nào đó gây nhầm lẫn với các chất kết dính được trả lại là một unary_function nhưng có vẻ khá tốt với boost::bind dù sao đi nữa. Ví dụ của tôi không có nghĩa là hoàn hảo vì nó không cho phép Func chuyển vào if_fun để quay lại và tôi đoán ai đó có thể chỉ ra nhiều sai sót hơn. Đề xuất được hoan nghênh.

+0

Tuyệt. Tôi cho rằng bây giờ tôi có thể thêm một hàm trợ giúp để khởi tạo một đối tượng 'if_fun' để tôi có thể giảm các tham số mẫu khi gọi' for_each() '... –

+0

boost :: bind hoạt động tốt như nhau với các hàm bình thường. class based Functors không thực sự cần thiết – bradgonesurfing

+0

Giải pháp này là địa ngục của một mess đơn giản. Tăng bộ điều hợp và phạm vi là những gì bạn muốn sử dụng ở đây. – newhouse

8

Bắt chước thuật toán giống như STL chính xác là những gì bạn nên làm. Đó là lý do tại sao họ đang ở trong STL.

Cụ thể, bạn có thể sử dụng hàm functor thay vì tạo hàm thực tế và liên kết nó. Điều này là nhiều neater, thực sự.

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()); 

Điều này thường được coi là cách thành ngữ.

+0

Tôi phải làm việc với các trình biên dịch ~ 10 C++, một số có niên đại từ cuối những năm 90. STL thực hiện trong nhiều người trong số họ là rất đa dạng, ngụ ý rằng S trong STL không đứng cho 'Tiêu chuẩn'. Đó là lý do tại sao tôi có xu hướng tránh immitating chức năng STL, và thay vì chỉ gọi cho họ. Tôi nghĩ rằng nếu for_each_if() là cách để giải quyết vấn đề, thì nó nên đã có trong STL, phải không? (Ý tôi là remove_if, find_if, count_if đã có). –

+1

@Grim: Mọi người thường chỉ gắn bó nếu trong functor của họ for for_each. Không cần thiết cho một cấu trúc for_each_if như vậy. – Puppy

4

Sử dụng bộ điều hợp dải tăng cường có nhiều nếp gấp.

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) 
    ) 

Lưu ý việc sử dụng các thư viện dòng sản phẩm mới để tóm tắt đi lặp ủng hộ của dãy và adapter phạm vi thư viện để soạn một đường ống dẫn hoạt động.

Tất cả các thuật toán dựa trên biến lặp stl tiêu chuẩn có được chuyển sang các thuật toán dựa trên phạm vi.

Hãy tưởng tượng này

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; 
    } 

đọc Range AdaptorsRange Algorithm.

+0

url tự động-> chuyển đổi a href bỏ qua thuật toán một, có lẽ là do độ dài. –

Các vấn đề liên quan