Search code examples
c++boostboost-multi-index

How to find all matches boost::multi_index with a key?


I have a boost::multi_index container. Could anybody tell me how to retrieve a range of iterators based on a certain key? After hours of search I got the idea that lower_bound or upper_bound should do the trick but I still do not got an example. In following example I would like to get all the iterators with price between 22 and 24. Thank you very much.

 struct order                                                      
 {                                                                 
     unsigned int    id;                                           
     unsigned int    quantity;                                     
     double          price;                                        

     order(unsigned int id_, unsigned int quantity_, double price_)
         :id(id_), quantity(quantity_), price(price_){}
}
typedef multi_index_container<                                    
  order,                                                          
  indexed_by<                                                     
    ordered_unique<                                               
      tag<id>,  BOOST_MULTI_INDEX_MEMBER(order, unsigned int, id),
      std::greater<unsigned int>>,                                
    ordered_non_unique<                                           
      tag<price>,BOOST_MULTI_INDEX_MEMBER(order ,double, price)>  
  >                                                               
> order_multi;                                                              
 int main()                                                            
 {                                                                     
     order_multi order_book;                                           

     order_book.insert(order(/*id=*/0, /*quantity=*/10, /*price=*/20));
     order_book.insert(order(/*id=*/1, /*quantity=*/11, /*price=*/21));
     order_book.insert(order(/*id=*/3, /*quantity=*/12, /*price=*/22));
     order_book.insert(order(/*id=*/2, /*quantity=*/1,  /*price=*/22));
    order_book.insert(order(/*id=*/4, /*quantity=*/1,  /*price=*/23));
    order_book.insert(order(/*id=*/5, /*quantity=*/1,  /*price=*/24));
    order_book.insert(order(/*id=*/6, /*quantity=*/1,  /*price=*/24));
    order_book.insert(order(/*id=*/7, /*quantity=*/1,  /*price=*/26));   

  }                                                                                                                                 

Solution

  • The range you're after is [lower_bound(22),upper_bound(24)), that is:

    auto first=order_book.get<price>().lower_bound(22);
    auto last=order_book.get<price>().upper_bound(24);
    for(;first!=last;++first)std::cout<<first->id<<" "; // prints 3 2 4 5 6
    

    If you find it confusing to determine when it's lower_ or upper_bound that you need to use, there is a range member function that is probably easier to get right (and marginally faster):

    auto range=order_book.get<price>().range(
      [](double p){return p>=22;},  // "left" condition
      [](double p){return p<=24;}); // "right" condition
    for(;range.first!=range.second;++range.first)std::cout<<range.first->id<<" ";
    

    provided you use C++11 and have lambda functions. You can also use range in C++03 without native lambda functions, but then you have to resort to Boost.Lambda or else write by hand the functors accepted by range, both of which options are probably too cumbersome.