読者です 読者をやめる 読者になる 読者になる

Boost.MultiIndexで複数のキーを持つ辞書 & インデックスを指定する2つの方法

C++

これがBoost.MultiIndexの最もよく使われるであろうユースケース
MultiIndexのインデックス指定方法は2つあり、まずはインデックスを整数値で指定する方法。

#include <iostream>
#include <string>
#include <algorithm>
#include <boost/mem_fn.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>

using namespace boost::multi_index;

struct person {
    int id;
    std::string name;
    int age;

    person(int id, const std::string& name, int age)
        : id(id), name(name), age(age) {}

    void print() const
        { std::cout << id << "," << name << "," << age << std::endl; }
};


typedef multi_index_container<
    person,
    indexed_by<
        ordered_unique<member<person, int,         &person::id> >,
        ordered_unique<member<person, std::string, &person::name> >,
        ordered_unique<member<person, int,         &person::age> >
    >
> dictionary;


template <int Index, class Container>
void print_by_index(const Container& c)
{
    typename Container::nth_index<Index>::type const& i = c.get<Index>();

    std::for_each(i.begin(), i.end(), boost::mem_fn(&person::print));
    std::cout << std::endl;
}


int main()
{
    dictionary dict;
    dict.insert(person(3, "Akira",  30));
    dict.insert(person(1, "Millia", 20));
    dict.insert(person(4, "Johnny", 10));

    print_by_index<0>(dict); // id順
    print_by_index<1>(dict); // name順
    print_by_index<2>(dict); // age順
}
1,Millia,20
3,Akira,30
4,Johnny,10

3,Akira,30
4,Johnny,10
1,Millia,20

4,Johnny,10
1,Millia,20
3,Akira,30


もうひとつは、インデックスをタグで指定する方法。

#include <iostream>
#include <string>
#include <algorithm>
#include <boost/mem_fn.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/multi_index/ordered_index.hpp>

using namespace boost::multi_index;

struct person {
    int id;
    std::string name;
    int age;

    person(int id, const std::string& name, int age)
        : id(id), name(name), age(age) {}

    void print() const
        { std::cout << id << "," << name << "," << age << std::endl; }
};

struct id{};
struct name{};
struct age{};

typedef multi_index_container<
    person,
    indexed_by<
        ordered_unique<tag<id>,   member<person, int,         &person::id> >,
        ordered_unique<tag<name>, member<person, std::string, &person::name> >,
        ordered_unique<tag<age>,  member<person, int,         &person::age> >
    >
> dictionary;


template <class Tag, class Container>
void print_by_tag(const Container& c)
{
    typename Container::index<Tag>::type const& i = c.get<Tag>();

    std::for_each(i.begin(), i.end(), boost::mem_fn(&person::print));
    std::cout << std::endl;
}


int main()
{
    dictionary dict;
    dict.insert(person(3, "Akira",  30));
    dict.insert(person(1, "Millia", 20));
    dict.insert(person(4, "Johnny", 10));

    print_by_tag<id>(dict);
    print_by_tag<name>(dict);
    print_by_tag<age>(dict);
}

インデックスに名前を付けられるので、タグを優先的に使ったほうがよさそう。