読者です 読者をやめる 読者になる 読者になる

boost::any_range

C++

Boost 1.46.0から、Boost.Rangeにany_rangeが導入されました。
any_rangeは、Type ErasureによってあらゆるRange型をlazy状態に保ったまま格納するための型で、Rangeアダプタの適用結果を変数に持つ場合や、Rangeアダプタの適用結果を関数の戻り値にしたい場合などに使用します。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/algorithm/for_each.hpp>

bool is_even(int x) { return x % 2 == 0; }
void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    boost::any_range<
        const int,
        boost::forward_traversal_tag,
        const int&,
        std::ptrdiff_t
    > r = v | boost::adaptors::filtered(is_even);

    boost::for_each(r, disp);
}
2
4

any_rangeのテンプレートパラメータは、最低でも以下の4つを指定することになっています:

  • 要素型
  • 横断コンセプト
  • 参照型
  • 差分型(difference type)

ありえないパラメータ数ですが、any_rangeは便利です。
ちなみにPStade.Ovenのany_rangeは参照型と横断コンセプトのみの指定で使用できます。


とりあえずTemplate Typedefしておけば書きやすくなると思います。

#include <iostream>
#include <vector>
#include <boost/assign/list_of.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/algorithm/for_each.hpp>

#include <boost/type_traits/add_reference.hpp>

template <class T, class Traversal>
struct short_any_range {
    typedef
        boost::any_range<
            T,
            Traversal,
            typename boost::add_reference<T>::type,
            std::ptrdiff_t
        >
    type;
};

bool is_even(int x) { return x % 2 == 0; }
void disp(int x) { std::cout << x << std::endl; }

int main()
{
    const std::vector<int> v = boost::assign::list_of(1)(2)(3)(4)(5);

    short_any_range<const int, boost::forward_traversal_tag>::type r =
        v | boost::adaptors::filtered(is_even);

    boost::for_each(r, disp);
}

何はともあれこれでやっと、アダプタの結果を変数に持とうとするだけで破綻するBoost.Rangeがより実用的になりました。