2011-09-07 11 views
6

Câu hỏi này được lấy cảm hứng từ another topic đó đặt ra câu hỏi này:Làm thế nào tôi có thể làm cho std :: find_if và std :: map làm việc cùng nhau bằng cách sử dụng một số thư viện tăng?

Tìm giá trị đầu tiên lớn hơn sử dụng giá trị quy định từ một container đồ

có thể được giải quyết bằng nhiều cách. Một giải pháp C++ 03 điển hình định nghĩa một hàm chuyên dụng (hoặc hàm functor) và chuyển nó tới một đối số thứ ba là std::find_if.

Trong C++ 11, người ta có thể tránh việc xác định một dành riêng chức năng (hoặc functor), và thay vào đó có thể tận dụng lambda như:

auto it = std:: find_if(m.begin(), mp.end(), 
        [n](const std::pair<std::string, int> & x) -> bool 
         { return x.second > n; } 
        ); 

đó là the accepted answer.

Tôi vẫn đang tìm một giải pháp ngắn và tuyệt vời. Nếu nó là một véc tơ, sau đó tôi chỉ học được một giải pháp tuyệt vời mà làm cho sử dụng Boost.Phoenix và dung dịch trở nên rất ngắn gọn (ideone demo):

std::vector<int> v = ...; 
auto it = std::find_if(v.begin(), v.end(), arg1 > 4); 

đây arg1 là một đối tượng functor quy định tại boost::phoenix::arg_names namespace, và sự biểu hiện arg1>4 đánh giá đến một hàm khác sau đó được chuyển đến std::find_if.

Một test nhanh là (ideone),

std::cout<< (arg1 > 9)(v) << std::endl; //prints 0 if as v > 9 is false, else 1 

//or store the functor first and then use it 
const auto & f = arg1 > 9; 
std::cout<< f(v) << std::endl; //prints 0 if as v > 9 is false, else 1 

Câu hỏi của tôi là, tôi muốn giải quyết vấn đề bản đồ, theo một cách tương tự. Có giải pháp nào như vậy không? Một cái gì đó như:

auto it = std::find_if(m.begin(),mp.end(), (???).second > n); //m is std::map 

Hoặc,

auto it = std::find_if(m.begin(),mp.end(), at<1>(arg1) > n); //m is std::map 

Đối với nó để làm việc, khái niệm at<1>(arg1) > 2 có để đánh giá một functor mà mất const std::pair & như là đối số. Cảm giác ruột của tôi nói với tôi rằng tăng cường có giải pháp này. :-)

+0

Bạn có muốn tìm chỉ các giá trị (trong trường hợp này http: // www.boost.org/doc/libs/release/libs/range/doc/html/range/reference/adaptors/reference/map_values.html là câu trả lời) hoặc trình lặp cho toàn bộ cặp khóa, giá trị trong đó giá trị thỏa mãn vị từ ? – Cubbi

+0

@Cubbi: Đó không phải là câu trả lời nếu điều đó không hoạt động với 'std :: find_if' trả về một trình lặp của bản đồ. – Nawaz

+0

@Nawaz: Tôi không biết nếu std :: find_if là bắt buộc. Nếu không, tôi sẽ đi với http://www.cplusplus.com/reference/stl/map/upper_bound/ mà nên được nhanh hơn, và chỉ có một dòng mã đơn giản. –

Trả lời

9

Thật vậy, Boost.Fusion và Boost.Phoenix có chính xác những gì bạn muốn tích hợp sẵn.

Nếu một bao gồm các tiêu đề cần thiết để adapt std::pair<> as a conforming Fusion sequence, sau đó người ta có thể sử dụng phiên bản lười biếng Phoenix của boost::fusion::at_c<> để truy cập std::pair<>::first hoặc std::pair<>::second (hãy chắc chắn #include <boost/phoenix/fusion.hpp>).

namespace phx = boost::phoenix; 
using phx::arg_names::arg1; 

auto it = std::find_if(m.begin(), m.end(), phx::at_c<1>(arg1) > n); 

EDIT: Full mẫu, thử nghiệm với VC++ 2010 SP1 + Boost 1.47.0:

#include <algorithm> 
#include <map> 
#include <string> 
#include <iostream> 
#include <boost/fusion/include/std_pair.hpp> 
#include <boost/phoenix/core.hpp> 
#include <boost/phoenix/operator.hpp> 
#include <boost/phoenix/fusion.hpp> 

int main() 
{ 
    namespace phx = boost::phoenix; 
    using phx::arg_names::arg1; 

    std::map<std::string, int> m; 
    m["foo"] = 1; 
    m["bar"] = 2; 
    m["baz"] = 3; 
    m["qux"] = 4; 
    m["quux"] = 5; 
    m["corge"] = 6; 
    m["grault"] = 7; 
    m["garply"] = 8; 
    m["waldo"] = 9; 
    m["fred"] = 10; 
    m["plugh"] = 11; 
    m["xyzzy"] = 12; 
    m["thud"] = 13; 

    int const n = 6; 
    auto it = std::find_if(m.cbegin(), m.cend(), phx::at_c<1>(arg1) > n); 
    if (it != m.cend()) 
     std::cout << it->first << '\n'; // prints "fred" 
} 
+0

Vui lòng gửi giải pháp làm việc và kiểm tra đầy đủ. Tôi không muốn nói rằng nó không biên dịch hay không làm việc. Mặc dù, tôi đang cố gắng làm những gì bạn gợi ý. – Nawaz

+0

@Nawaz: Đã chỉnh sửa. – ildjarn

+0

Được rồi. Tôi đã thử biên dịch nó và không thành công khi biên dịch: http://ideone.com/EgALC – Nawaz