どういうことがしたいかというと、
for (vector<string>::iterator it = lis.begin(); it != lis.end(); ++it) { cout << *it << endl; }
のようなループをかくのが面倒なので
cout << lis << endl;
のように書きたい。
これをやるにはtemplateパラメータにtemplateをつかってoperator<<をオーバーロードしてやればまあまあ簡単にかける。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <map> | |
#include <vector> | |
#include <string> | |
#include <set> | |
using namespace std; | |
template <typename T, typename U> | |
ostream& operator<<(ostream& os, const pair<T, U> p) { | |
os << p.first << ':' << p.second; | |
return os; | |
} | |
template <typename T, typename Alloc, | |
template <typename _1, typename _2> class Container> | |
ostream& operator<<(ostream& os, const Container<T, Alloc >& p) { | |
typename Container<T, Alloc>::const_iterator e = p.end(); | |
os << '['; | |
for (typename Container<T, Alloc>::const_iterator it = p.begin(); it != e;) { | |
os << *it; | |
os << (++it == e ? "" : ", "); | |
} | |
os << ']'; | |
return os; | |
} | |
template <typename T, typename Alloc, | |
template <typename _1, typename _2, typename _3> class Container> | |
ostream& operator<<(ostream& os, const Container<T, less<T>, Alloc>& p) { | |
typename Container<T, less<T>, Alloc>::const_iterator e = p.end(); | |
os << '['; | |
for (typename Container<T, less<T>, Alloc>::const_iterator it = p.begin(); it != e;) { | |
os << *it; | |
os << (++it == e ? "" : ", "); | |
} | |
os << ']'; | |
return os; | |
} | |
template <typename T, typename Alloc, | |
template <typename _1, typename _2, typename _3> class Container> | |
ostream& operator<<(ostream& os, const Container<T, greater<T>, Alloc>& p) { | |
typename Container<T, greater<T>, Alloc>::const_iterator e = p.end(); | |
os << '['; | |
for (typename Container<T, greater<T>, Alloc>::const_iterator it = p.begin(); it != e;) { | |
os << *it; | |
os << (++it == e ? "" : ", "); | |
} | |
os << ']'; | |
return os; | |
} | |
template <typename T, typename U, typename Compare, typename Alloc, | |
template <typename _1, typename _2, typename _3, typename _4> class Container> | |
ostream& operator<<(ostream& os, const Container<T, U, Compare, Alloc>& p) { | |
typename Container<T, U, Compare, Alloc>::const_iterator e = p.end(); | |
os << '{'; | |
for (typename Container<T, U, Compare, Alloc>::const_iterator it = p.begin(); it != e; ) { | |
os << *it; | |
os << (++it == e ? "" : ", "); | |
} | |
os << '}'; | |
return os; | |
} | |
int main() { | |
vector<int> ary; | |
ary.push_back(1); | |
ary.push_back(2); | |
ary.push_back(3); | |
cout << ary << endl; // [1, 2, 3] | |
set< string > lis1; | |
lis1.insert("foo"); | |
lis1.insert("bar"); | |
lis1.insert("baz"); | |
cout << lis1 << endl; // [bar, baz, foo] | |
map<int, vector<int> > lis2; | |
lis2.insert(make_pair(1, ary)); | |
ary.pop_back(); | |
lis2.insert(make_pair(2, ary)); | |
ary.clear(); | |
lis2.insert(make_pair(3, ary)); | |
cout << lis2 << endl; // {1:[1, 2, 3], 2:[1, 2], 3:[]} | |
} |
forward_iteratorを実装してるコンテナならなんでもいけるはず。ネストしててもOK
テンプレートパラメータが3つのコンテナ用の定義でlessとgreaterに分けてるのは、コンパイラに型推論をうまくやってもらうため。(テンプレートパラメータだけではstringの型と見分けがつかないので)
2011-06-04追記
古いコンパイラだとコンパイルできないかも