C++ stl map의 사용자 정의 타입을 key로 사용하는 방법
map의 키는 주로 int 값을 이용하거나,
map<int, bool> m;
m[5] = true;
또는 int 2개의 값을 키로 사용해야 한다면 __int64 자료형을 이용할 수 있습니다.
map<__int64, bool> m;
m[5] = true;
문제는 128bit로 넘어갈 때입니다. Visual C++의 경우 명시적인 128bit 자료형이 없는데요. (살짝 이해할 수 없는 것이 32비트 플랫폼에서도 __int64를 제공하면서 왜 64비트 플랫폼에서 __int128 같은 자료형을 제공하지 않고 있는지 의문입니다. ^^)
어쩔 수 없습니다. 그런 경우에는 map의 키로써 사용할 수 있는 조건을 갖춰 새롭게 사용자 정의 타입을 만들어야 합니다.
How can I use std::maps with user-defined types as key?
; https://stackoverflow.com/questions/1102392/how-can-i-use-stdmaps-with-user-defined-types-as-key
Why C++ STL containers use “less than” operator< and not “equal equal” operator== as comparator?
; https://stackoverflow.com/questions/27153303/why-c-stl-containers-use-less-than-operator-and-not-equal-equal-operator
조건은 단 하나! 그냥 '<' 연산자만 제공하면 됩니다.
#include <iostream>
#include <map>
using namespace std;
class Class1
{
public:
Class1(int id, int subid) : id(id), subid(subid) {};
bool operator < (const Class1& rhs) const
{
if (id == rhs.id)
{
return subid < rhs.subid;
}
return id < rhs.id;
}
private:
int id;
int subid;
};
int main()
{
{
Class1 c1(1, 5);
map<Class1, int> c2int;
c2int[c1] = 12;
Class1 c2(1, 6);
c2int[c2] = 16;
Class1 c3(2, 6);
c2int[c3] = 18;
Class1 c4(2, 6);
c2int[c4] = 20;
for (auto iter = c2int.begin(); iter != c2int.end(); iter++)
{
std::cout << (*iter).second << endl;
}
}
std::cout << endl;
}
operator 구현을 분리하고 싶다면 friend 예약어를 이용해 이렇게 구현하는 것도 가능합니다.
#include <iostream>
#include <map>
class Class1
{
public:
Class1(int id) : id(id) {};
private:
int id;
friend class Class1Compare;
};
struct Class1Compare
{
bool operator() (const Class1& lhs, const Class1& rhs) const
{
return lhs.id < rhs.id;
}
};
int main()
{
{
Class1 c1(1);
map<Class1, int> c2int;
c2int[c1] = 12;
}
std::cout << "Hello World!\n";
}
또는, 기존 std::less 타입을 재사용해 (그래도 코드가 딱히 줄어들지는 않지만) template으로 정의하는 것도 가능합니다.
#include <iostream>
#include <map>
using namespace std;
class Class1
{
public:
Class1(int id) : id(id) {};
private:
int id;
friend struct std::less<Class1>;
};
namespace std
{
template<> struct less<Class1>
{
bool operator() (const Class1& lhs, const Class1& rhs) const
{
return lhs.id < rhs.id;
}
};
}
int main()
{
{
Class1 c1(1);
map<Class1, int> c2int;
c2int[c1] = 12;
}
std::cout << "Hello World!\n";
}
그런데,
C#의 IComparer 구현에 익숙하신 분들은 위의 C++ 코드가 좀 낯설지 않나요? ^^ 왜냐하면, 보통 C#에서는 >, ==, < 상황에 대해 1/0/-1을 반환하는 식으로 처리하는데 위의 C++ 코드는 단순하게 "return lhs.id < rhs.id;" 한 가지 조건으로 bool 반환만을 하기 때문입니다.
이것이 가능한 이유는, 어차피 위의 조건에서 false를 반환하면 "<" 조건을 나타낼 수 있고, '==' 처리는 "!(a<b) && !(b<a)" 식으로 알아낼 수 있기 때문이라고 합니다.
(
첨부 파일은 이 글의 예제 코드를 포함합니다.)
[이 글에 대해서 여러분들과 의견을 공유하고 싶습니다. 틀리거나 미흡한 부분 또는 의문 사항이 있으시면 언제든 댓글 남겨주십시오.]