boost::range

トップページ > コンテナとイテレータ >

abstract

必要なヘッダ
<boost/range.hpp>
出来ること
"Range"のconcept定義と、操作関数
リファレンス
en

sample

#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#include <boost/range.hpp>
using namespace std;
using namespace boost;

// Rangeの全ての要素を表示
template<typename Range>
  void print( Range& r )
  {
      typename
        range_const_iterator<Range>::type i = begin(r), e = end(r);
      for(; i!=e; ++i)
          cout << *i << endl;
  }

// 補助関数(10進の桁数の大小を比較)
bool cmp_digits( int a, int b )
  { return (int)log10((double)a) < (int)log10((double)b); }

// 2ケタの範囲を表示
int main()
{
    int sorted[] = {1,2,3,45,67,89,123,456,7890};
    print( sorted );
    cout << endl;
    print( std::equal_range(begin(sorted), end(sorted), 99, &cmp_digits) );
}

出力例

1
2
3
45
67
89
123
456
7890

45
67
89

etc

STLのアルゴリズムは「イテレータ」という、データ列中の位置、一点を指す概念を元に設計されています。 「ここからここまで」のような「範囲」を表現したければ、2個のイテレータを使って表すことになります。 そうじゃなくて、直接「範囲」を表すオブジェクトというのを考えてみたらどうでしょう?というのが、 Rangeライブラリの提案です。

上のコードは、「2個のイテレータ」では綺麗に表せないけれど、 「範囲」として記述すれば綺麗に書ける例としてあげてみました。 print関数テンプレートは、「範囲」を受け取ってその要素を先頭から順番に標準出力に表示してます。 boost/range.hpp ヘッダを読み込むと、配列やSTLのコンテナ、イテレータのstd::pairなどに begin/end関数が適用できて、イテレータが取得できるのようになってますので、print(sorted) で配列の中身が全部表示できます。

STL的な書き方だと、このprint関数は print(Iterator beg, Iterator end) と2つイテレータを取る形で定義するのが普通だと思います。でもこれを「範囲」を受け取るように定義すると、 色々便利になります…!というのが次の行です。 std::equal_rangeはstd::pair<iterator,iterator>というイテレータの組を返値として返しますが、 イテレータのpairは「範囲」として扱えるので、そのままprintの引数にできます。 もしprintがiterator2つを引数にとるのだったら、equal_rangeの返値をいったん変数に保存して print(p.first,p.second)という不格好なコードを書かなければなりません。

see also

Boost.Range自体はRangeを扱うインターフェイス(begin/end関数とrange_iteratorテンプレート)を決めて、 標準のコンテナ他1くつかをRangeとして扱えるように定義しているだけの小さなライブラリです。

実際にRangeの威力を発揮するには、Rangeをフル活用したアルゴリズムライブラリが不可欠です。 既にいくつかRangeベースのライブラリが登場しています。

presented by k.inaba (kiki .a.t. kmonos.net) under CC0