3

I have created a boost::multi_index successfully and inserted values too. I have two hashed indices to the multi_index. Both are member functions, but one is unique and the other one is non-unique.

I am trying to figure out the way to get the values from the container using the values of the hashes. I could not understand how I should do that. I searched online, and I see there are a lot of people have asked this question. But I dont understand what needs to be done. I saw a few solutions in C++11 but I dont use C++11 and I dont understand whats being done. Can someone please explain to me how to use it? Given below is my code,

#include "stdafx.h"
#include<multi_index_container.hpp>
#include<boost/multi_index/hashed_index.hpp>
#include<boost/multi_index/mem_fun.hpp>
#include<boost/multi_index/tag.hpp>



class RetClass
{
    int a, b;
};

class StoreMe
{
    RetClass ex;
    std::string exStr;
    int id;
public:
    void setId(RetClass a) 
    {
        ex = a;
    };


    virtual const RetClass& getId() const { return ex; }
    virtual std::string getIdString() const { return exStr; }
    int getUniqueId() const { return id; }
};

struct IndexByStringId{};
struct IndexByUniqueId{};

typedef boost::multi_index_container<
    StoreMe,
    boost::multi_index::indexed_by<
        boost::multi_index::hashed_unique<
            boost::multi_index::tag<IndexByStringId>,
            boost::multi_index::const_mem_fun<StoreMe, std::string,     &StoreMe::getIdString> 
        >,
        boost::multi_index::hashed_non_unique<
            boost::multi_index::tag<IndexByUniqueId>,
            boost::multi_index::const_mem_fun<StoreMe, int,     &StoreMe::getUniqueId> 
        >
    >
> mi_storeMe;

int _tmain(int argc, _TCHAR* argv[])
{
    return 0;
}

I want to be able to,

  1. Get the values non-unique Id maps to
  2. Get the value (if it exists) that the unique Id maps to

Please let me know the correct/simplest way to get this done. Also I don't use C++11.

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
codeworks
  • 149
  • 1
  • 15

1 Answers1

1

Here's how you'd retrieve from the string-based index:

mi_storeMe container;

std::string needle = whatToSearchFor();
auto iterator = container.get<IndexByStringId>().find(needle);
if (iterator != container.get<IndexByStringId>().end())
  found(*iterator);
else
  notFound();

For the ID-based index, it's very similar:

mi_storeMe container;

RetClass needle = whatToSearchFor();
auto range = container.get<IndexByUniqueId>().equal_range(needle);
processRangeFromTo(range.first, range.second);

The answer uses auto from C++11 so that I can avoid spelling out the types involved. If you do not have access to C++11, please do the type deduction yourself by reading Boost's multi_index documentation. I cannot vouch for correctness, but I believe the iterator type can be spelled as

mi_storeMe::index<IndexByStringId>::type::iterator

Tangentially related: how to do printf-style debugging of multi-index containers without C++11.

First off, remember thatwhile you don't have auto, you still have type deduction in templates. No need to spell out types if a function template can deduce them:

template <class It>
void printContainerItems(It from, It to) {
  for (; from != to; ++from)
    print(*from);
}

printContainerItems(container.begin(), container.end());

Second, you can easily iterate over an index:

const mi_Container::index<IndexByIdString>::type& index = container.get<IndexByIdString>();
for (
  mi_Container::index<IndexByIdString>::type::iterat‌​or it = index.begin(), end = index.end();
  it != end;
  ++it
)
{
  operate_on(*it);
}
Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455
  • Is this fine @Agnew? `std::pair::type::iterator, mi_Container::index::type::iterator> range_it = Containers.get().equal_range(nonEqId); if (range_it.first != Containers.get().end()) //If it was found {//We might have a range of values for (mi_Container::index::type::iterator it = range_it.first; it != range_it.second; it++) { value = *it; //Get the value pointed by the iterator, do what I want on "value" . . .` – codeworks Oct 20 '16 at 01:47
  • @codeworks It looks OK at a glance, but why don't you ask your compiler & program? ;-) – Angew is no longer proud of SO Oct 20 '16 at 06:39
  • @Agnew, I checked already. I posted for a confirmation since the equal_range does return an empty range(i.e first and last iterator equal to end()) – codeworks Oct 20 '16 at 08:04
  • @codeworks Do note that in your Q, the `IndexByStringId` is `hashed_unique`, and the `IndexByUniqueId` is `hashed_non_unique`. You might want to double-check your setup in real code, and/or use debugging outputs of the whole container (by traversing it through an arbitrary index) to make sure it contains what you think it does. – Angew is no longer proud of SO Oct 20 '16 at 08:11
  • @Agnew, I will check that, thanks for pointing that out. I wanted to traverse through the container and see what it contains, but I found a mi_StoreMe::begin(), mi_StoreMe()::end() or it but could not find a mi_StoreMer::iterator. How do I iterate through the whole thing(without using a list of a key). Infact this was my first idea to debug this. Please let me know how I get all the values stored in m_StoreMe. Thanks – codeworks Oct 20 '16 at 08:37
  • @codeworks I added a few C++03-friendly traversal options to the answer. – Angew is no longer proud of SO Oct 20 '16 at 08:47