boost::range
stlのlist等、ランダムアクセスイテレータが使えないコンテナは添え字アクセスもat()によるアクセスもできなくて不便。なので、boost::rangeでこんなのを作ってみた。
#include <stdexcept> #include <boost/range.hpp> template <typename RangeType> typename boost::range_reference<RangeType>::type GetElementAt(RangeType& Range, int Index) { using namespace boost; int i = 0; /* range_mutable_iterator<RangeType>::type it = begin(Range); */ range_iterator<RangeType>::type it = begin(Range); for (it ; it != end(Range) ; ++ it) { if (i == Index) { return *it; } ++ i; } throw std::out_of_range("GetElementAt : out of range"); }
こんな感じで要素を取得。
list<int> IntList; IntList.push_back(1); IntList.push_back(2); IntList.push_back(3); int Ret = GetElementAt(IntList, 1);
[]やat持ちのコンテナの場合はそちらを使うようにする事はできるのだろうか?vectorとかに対して使うとパフォーマンス的に問題なので。イテレータの種類が判定できればいけそうだけど……
ちょっとグーグル先生にお伺いしつつランダムアクセスイテレータの場合は添え字アクセスで返すように頑張ってみた。
template <typename T> bool IsRandomAccessIterator(T it) { return false; } bool IsRandomAccessIterator(std::random_access_iterator_tag it) { return true; } template <typename RangeType> typename boost::range_reference<RangeType>::type GetElementAt(RangeType& Range, int Index) { using namespace boost; using namespace std; if (IsRandomAccessIterator(iterator_traits<range_iterator<RangeType>::type>::iterator_category())) { return Range[Index]; } else { int i = 0; /* range_mutable_iterator<RangeType>::type it = begin(Range); */ range_iterator<RangeType>::type it = begin(Range); for (it ; it != end(Range) ; it ++) { if (i == Index) { return *it; } ++ i; } throw std::out_of_range("GetElementAt : out of range"); } }
当然コンパイルエラーだよと。イテレータの種類って静的に判別できないのかな……
というか、listをindex指定でアクセスしたい!という理由で作ったけど、実はdequeで良い事が発覚したので結局使い道が無かったという。