#include <set>
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
//#include <windows.h>
// ↓代替の定義
namespace
{
typedef long LONG;
typedef struct tagPOINT
{
    LONG  x;
    LONG  y;
} POINT;

}	// namespace

namespace
{
class CNode
{
	public:
	POINT position;
	int key1;
	int key2;
	int key3;
	CNode()
	{
		position.x=rand()%2;
		position.y=rand()%2;
		key1=rand()%3;
		key2=rand()%5;
		key3=rand()%10;
	}
};

/// CNodeへのポインタを保持するクラス
/// これはbool operator<(const T& lhs, const T& rhs)がTがクラス型でないとエラーになるので
/// 回避のため設ける。
struct CNodeHolder
{
	CNode* m_pObj;
	CNodeHolder(CNode* p) : m_pObj(p) { }
};

bool operator<(const CNodeHolder& lhs, const CNodeHolder& rhs)
{
	const POINT& a = lhs.m_pObj->position;	// Alias
	const POINT& b = rhs.m_pObj->position;	// Alias
	if (a.x != b.x) {
		return (a.x < b.x);
	} else if (a.y != b.y) {
		return (a.y < b.y);
	} else {
		return false;
	}
}

/// Optional. 定義してあれば実行効率が増す(ﾊｽﾞ)
bool operator==(const CNodeHolder& lhs, const CNodeHolder& rhs)
{
	return (
		   lhs.m_pObj->position.x == rhs.m_pObj->position.x
		&& rhs.m_pObj->position.y == rhs.m_pObj->position.y	);
}

typedef std::set<CNodeHolder> NODE_POINTER_SET;

}	// namespace

int main()
{
	srand((unsigned)time(NULL));

	int NUM=100;
	printf("setへの登録候補数:%d\n",NUM);
	NODE_POINTER_SET NodePointerSet;
	for(int i=0; i<NUM; i++)
	{
		CNode* const node = new CNode();
		printf("%x:(%d,%d)【%3d %3d %3d】をセットへ\n"
			,node
			,node->position.x, node->position.y
			,node->key1, node->key2, node->key3 );
		CNodeHolder holder(node);
		//重複登録にならないかfind()で確かめてから登録
		//find()せずにinsert()すると登録してしまうのでnodeが生ポインタな今回の基本設計下ではﾔｳﾞｧｲ。
		auto found_it = NodePointerSet.find(holder);
		if (found_it == NodePointerSet.end()) {
			//重複登録にならないので追加する。
			NodePointerSet.insert(holder);
		} else {
			//重複登録になるので(追加を行わずに)確保したメモリを破棄する。
			delete node;
		}
	}

	printf("\nset内に登録された要素数:%d\n",NodePointerSet.size());
	for(NODE_POINTER_SET::const_iterator it=NodePointerSet.begin(); it!=NodePointerSet.end(); )
	{
		printf("%x:(%d,%d)【%3d %3d %3d】をセットから\n"
			,*it
			,(*it).m_pObj->position.x, (*it).m_pObj->position.y
			,(*it).m_pObj->key1, (*it).m_pObj->key2, (*it).m_pObj->key3 );
		delete (*it).m_pObj; //メモリの後始末
		it=NodePointerSet.erase(it); //setから削除 itは次の要素を指す
	}
}
