Question

This code is adopted from the boost multi-index "mru" example:

http://www.boost.org/doc/libs/1_46_1/libs/multi_index/example/serialization.cpp

I have code that is doing something similiar as a boost::unordered_map, but I would really like to add the mru functionality from this example.

I would like to make this code work as close to having a boost::unordered_map as possible. The key feature for me is the [] operator of the unordered_map.

The final lines of main() are broken and above each line as a comment is my question.

Thanks in advance to all answers comments.

#include <algorithm>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <iostream>

using namespace boost::multi_index;

class my_struct {
public:
    my_struct(int in_a, std::string in_b) : a(in_a), b(in_b) {}

    int a;
    std::string b;

    bool operator==(const my_struct &rhs) const
    {
        return (a == rhs.a);
    }
    bool operator!=(const my_struct &rhs) const
    {
            return !(*this == rhs);
    }

    friend std::ostream& operator<<(std::ostream &out, const my_struct&ms);
};

std::ostream& operator<<(std::ostream &out, my_struct &ms)
{
    out << ms.a << " " << ms.b << std::endl;
    return out;
}

inline std::size_t
hash_value(const my_struct &val)
{
    return boost::hash_value(val.a);
}

// tags for multi_index
struct umap {};
template <typename Item>
class mru_list
{
  typedef multi_index_container<
    Item,
    indexed_by<
      sequenced<>,
      hashed_unique<boost::multi_index::tag<umap>, identity<Item> >
    >
  > item_list;

public:

  typedef Item                         item_type;
  typedef typename item_list::iterator iterator;

  mru_list(std::size_t max_num_items_):max_num_items(max_num_items_){}

  void insert(const item_type& item)
  {
    std::pair<iterator,bool> p=il.push_front(item);

    if(!p.second){                     /* duplicate item */
      il.relocate(il.begin(),p.first); /* put in front */
    }
    else if(il.size()>max_num_items){  /* keep the length <= max_num_items */
      il.pop_back();
    }
  }

  iterator begin(){return il.begin();}
  iterator end(){return il.end();}

//private:
  item_list   il;
  std::size_t max_num_items;
};

int main()
{
    mru_list<my_struct> mru(10);
    my_struct one(1, "One");

    mru.insert(one);
    mru.insert(my_struct(2, "Two"));
    mru.insert(my_struct(3, "Three"));
    mru.insert(one);

    std::cout<<"most recently entered terms:"<<std::endl;
    for (mru_list<my_struct>::iterator itr = mru.begin(); itr != mru.end(); ++itr) {
        std::cout << itr->a << std::endl;
    }

    // what is my return type?
    mru.il.get<umap>();

    // Why doesn't this work?
    mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);

    // Why doesn't this have a [] operator like boost:unordered_map
    mru.il.get<umap>()[1] = "foobar";

    return 0;
}
Was it helpful?

Solution

// what is my return type?

mru.il.get<umap>();

Its return type is the type of your umap index, which is:

  typedef typename boost::multi_index::index<
        item_list
      , umap
      >::type hashed_index_t;

  mru_list<my_struct>::hashed_index_t& hashed_index = mru.il.get<umap>();

In C++11 it is easier with auto:

  auto& hashed_index = mru.il.get<umap>();

// Why doesn't this work?

mru_list<my_struct>::iterator itr = mru.il.get<umap>().find(one);

find() returns an iterator of umap (second) index and the above statement is assigning it to the iterator of the first index. There are projection operations to convert from one index iterator type to another iterator type of the same multi-index container, e.g.:

mru_list<my_struct>::iterator itr = project<0>(mru.il, hashed_index.find(one));

// Why doesn't this have a [] operator like boost:unordered_map

Can't say why, it just doesn't.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top