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

[set](http://qiita.com/izmktr/items/17e3009041b841b26a34)や[unorderd_set](http://qiita.com/izmktr/items/8e0fd1b6e37de59a9bd0)でやってきたことのmulti_index_containor編です。

multi_index_containorそのものの解説は、ぐぐったりして調べてください。
慣れるとめちゃくちゃ便利なコンテナです。

setに当たるものがorderd_unique、unorderd_setにあたるものがhashed_uniqueになります。
ちなみに、multi_setがorderd_non_unique、unorderd_multisetがhashed_non_uniqueです。

multi_index_containorの場合は、色々便利な関数が揃っているので、
比較関数やハッシュ関数を登録せずに使う方法もあります。

#クラスに必要な関数をもたせる

まずは、クラスそのものに必要な関数を定義してしまう方法です。
前回まではPoint型を例に、yの値のみをキーにしていましたが、今回はxとyの両方をキーにしています。

orderd_uniqueならoperator<を定義します。
hashed_uniqueならoperator==とhash_valueを定義します。
それぞれ、std::mapとboost::unorderd_mapと同じ方法です。

```cpp
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/hashed_index.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){}

	bool operator<(const Point &r) const { return this->x == r.x ? this->y < r.y : this->x < r.x; }
	bool operator==(const Point &r) const { return this->x == r.x && this->y == r.y; }
	friend size_t hash_value(const Point &p){ return (p.x << 16) ^ (p.x >> 16) ^ p.y; }
};

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

int main(){
	PointIndex p;

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

	return 0;
}
```
#composite_keyで複数のキーを指定する
Point型はxとyの値を持ったクラスなので、この両方をcomposite_keyとして一つにまとめたキーとして扱うことでもできます。
この時、複数のint型という扱いなので、特に自分で関数を用意する必要はありません。

```cpp
#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>
#include <boost/multi_index/composite_key.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 boost::multi_index_container <
	Point,
	indexed_by<
	hashed_unique<composite_key_point>,
	ordered_unique<composite_key_point>
	>
> PointIndex;

int main(){
	PointIndex p;

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

	return 0;
}
```
#関数を使って一つにまとめる
Point型にあるxとyはint型なので、intを32bitと考えるとPointは64bitのデータを持ちます。
long long(64bit)の値を返す関数を定義して、それで管理するという方法をやってみます。

hashed_uniqueの方は侵入型(メンバ関数を呼び出す形)、orderd_uniqueの方は非侵入型(グローバル関数を呼び出す形)で定義しています。

```cpp
#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){}

	long long int64value() const{
		return (static_cast<long long>(x) << 32) | y;
	}
};

long long point_int64value(const Point &p){ return p.int64value(); }

typedef boost::multi_index_container <
	Point,
	indexed_by<
		hashed_unique<BOOST_MULTI_INDEX_CONST_MEM_FUN(Point, long long, int64value)>,
		ordered_unique< global_fun<const Point &, long long, &point_int64value> >
	>
> PointIndex;

int main(){
	PointIndex p;

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

	return 0;
}

```

BOOST_MULTI_INDEX_MEMBERを使う場合、自分自身が直接所有しているメンバ変数しか指定できません。
PointData型の中にPoint型があり、Point型のxとyを指定したいという場合は、
BOOST_MULTI_INDEX_MEMBERではうまくできないので、ラッパ関数を作って対応します。

(BOOST_MULTI_INDEX_MEMBERを入れ子にする方法があるなら教えて欲しいです。)

```cpp

#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>
#include <boost/multi_index/composite_key.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 PointData{
	Point pos;
	int value;

	PointData(const Point &pos, int value):pos(pos), value(value){}
	PointData():pos(), value(0){}
};

int PointDataPointX(const PointData &pd){return pd.pos.x;}
int PointDataPointY(const PointData &pd){return pd.pos.y;}

typedef composite_key < 
	PointData, 
	global_fun<const PointData &, int, &PointDataPointX>,
	global_fun<const PointData &, int, &PointDataPointY>
> composite_key_point;

typedef boost::multi_index_container <
	PointData,
	indexed_by<
		hashed_unique<composite_key_point>,
		ordered_unique<composite_key_point>
	>
> PointDataIndex;

int main(){
	PointDataIndex p;

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

	return 0;
}
```

長くなったので、比較関数を指定する方法に関しては次回に書きます。