1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

multi_index_containerのキーに任意のクラスを使用する(2)

Last updated at Posted at 2015-07-30

前回の続きです
今回は、実際に比較関数を渡していきます。

#テンプレートの引数で指定する
関数オブジェクトをテンプレートの引数で指定する方法です。
これも、mapやunorded_mapと同じ方法なので簡単です。

structを使った関数オブジェクトを作るのが面倒ではありますが、
後に紹介するコンストラクタを使って指定するよりは楽です。

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
#include <boost/multi_index/global_fun.hpp>
using namespace boost::multi_index;

struct Point{
    int x, y;

    Point() :x(0), y(0){}
    Point(int x, int y) :x(x), y(y){}
};

struct PointCompare{
	bool operator()(const Point &l, const Point &r) const {
		return l.x == r.x ? l.y < r.y : l.x < r.x;
	}
};

struct PointEqual{
	bool operator()(const Point &l, const Point &r) const {
		return l.x == r.x && l.y == r.y;
	}
};

struct PointHash{
	size_t operator()(const Point &p) const {
		return  (p.x << 16) ^ (p.x >> 16) ^ p.y;
	}
};

typedef boost::multi_index_container <
    Point,
    indexed_by<
    ordered_unique< identity<Point>, PointCompare >,
    hashed_unique< identity<Point>, PointHash, PointEqual >
    >
> PointIndex;

int main(){
    PointIndex p;

    p.insert(Point(10, 20));
    p.insert(Point(20, 30));
    p.insert(Point(0, 10));

    return 0;
}

#composite_keyでのテンプレートの引数にする
orderd_indexにcomposite_keyを渡している場合、比較関数を指定することで昇順と降順を入り混ぜる場合事もできます。
hashed_uniqueを場合は、任意のクラスをcomposite_keyの一つにしている場合、ハッシュ関数を渡すという使い方ができます。
ちなみに、unorderd_mapやhashed_uniqueのとき、equal_toの方はoperator==が定義されているなら省略できます。
等号が使えるクラスは多いので、そういうクラスを使う場合はハッシュ関数だけ定義すればいいです。


#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/composite_key.hpp>
#include <boost/multi_index/member.hpp>

using namespace boost::multi_index;

struct Point{
    int x, y;

    Point() :x(0), y(0){}
    Point(int x, int y) :x(x), y(y){}
};

typedef composite_key < 
    Point, 
    BOOST_MULTI_INDEX_MEMBER(Point, int, x),
    BOOST_MULTI_INDEX_MEMBER(Point, int, y)
> composite_key_point;

typedef composite_key_compare <
    std::less<int>,
    std::greater<int>
> composite_key_compare_point;

typedef composite_key_hash <
    std::hash<int>,
    std::hash<int>
> composite_key_hash_point;

typedef composite_key_equal_to <
    std::equal_to<int>,
    std::equal_to<int>
> composite_key_equal_point;

typedef boost::multi_index_container <
    Point,
    indexed_by<
        hashed_unique<composite_key_point, composite_key_hash_point, composite_key_equal_point>,
        ordered_unique<composite_key_point, composite_key_compare_point>
    >
> PointIndex;

int main(){
    PointIndex p;

    p.insert(Point(10, 20));
    p.insert(Point(20, 30));
    p.insert(Point(0, 10));

    return 0;
}

#コンストラクタで指定する
ラムダ式だったり関数ポインタだったりを渡したい場合はコンストラクタで指定します。
これも今までの記事を読んでた人には容易に予想できる展開ですが、
multi_index_containorのコンストラクタは指定するものが多くて苦労します。

コンストラクタで指定するには、boost::tupleを使います。
orderd_uniqueの場合は"tuple<key_from_value,key_compare>"が必要です。
hashed_uniqueの場合は、"tuple<size,key_from_value,hasher,key_equal>"が必要です。

そして、これらを個数分だけさらにboost::tupleで囲みます。
特に指定するものがなかったり、デフォルトで良い場合は"ctor_args"を使います。

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/member.hpp>

using namespace boost::multi_index;

struct Point{
    int x, y;

    Point() :x(0), y(0){}
    Point(int x, int y) :x(x), y(y){}
};

typedef boost::multi_index_container <
	Point,
	indexed_by<
	hashed_unique< identity<Point>, size_t(*)(const Point &), bool(*)(const Point &, const Point &)>,
	ordered_unique< identity<Point>, bool(*)(const Point &, const Point &)>
	>
> PointIndex;

int main(){
	//デフォルトにする場合 ()
    //ただし、関数を指定していないのでinsertを使うとエラーが出る。 
	PointIndex::ctor_args_list args1 = boost::make_tuple(
		PointIndex::nth_index<0>::type::ctor_args(),
		PointIndex::nth_index<1>::type::ctor_args()
		);
	PointIndex p1(args1);

	auto hash = [](const Point &p)->size_t{return (p.x << 16) ^ (p.x >> 16) ^ p.y; };
	auto equal = [](const Point &l, const Point &r){return l.x == r.x && l.y == r.y; };
	auto compare = [](const Point &l, const Point &r){return l.x == r.x ? l.y < r.y : l.x < r.x; };

	//関数を指定する場合  
	PointIndex::ctor_args_list args2 = boost::make_tuple(
		boost::make_tuple(0, identity<Point>(), hash, equal),
		boost::make_tuple(identity<Point>(), compare)
		);
	PointIndex p2(args2);

    p2.insert(Point(10, 20));
    p2.insert(Point(20, 30));
    p2.insert(Point(0, 10));

    return 0;
}

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?