setに渡す比較関数をBoost.Lambdaで指定

最近twitterid:thincaさんが、boost::shared_ptrにくるんだoperator<の定義してあるクラスをstd::setに、そのクラスのoperator<で比較した順序で格納されるようにしたいってツイートしてて、BoostのMLで丁度同じ話題が出てました。

Using boost::shared_ptr with std::set
比較関数オブジェクト作ればいいけど、Boostならもっと短くしてくれるよね?って。

そこで解答として

  • boost/utility/compare_pointees.hpp を使う方法
  • type数少なめな比較関数の実装を使う方法
  • Boost.Lambdaを使う方法

の3つが挙げられてました。

Boost.Lambdaを使う方法は

#include <iostream>
#include <set>
#include <boost/lambda/lambda.hpp>
#include <boost/make_shared.hpp>
#include <boost/typeof/typeof.hpp>

#include <pstade/oven/foreach.hpp>

class A
{
public:
    A(int n = 0) : n(n) {}

    int n;
    bool operator < (A const &a) const { return this->n < a.n; }
};

typedef boost::shared_ptr<A>    pa_t;

namespace bll = boost::lambda;
typedef std::set<pa_t, BOOST_TYPEOF(*bll::_1 < *bll::_2)>   set_t;

int main()
{
    set_t   s(*bll::_1 < *bll::_2);
    for(int i = 0; i < 10; ++i) {
        s.insert(boost::make_shared<A>((i%2)?i:-i));
    }

    PSTADE_OVEN_FOREACH(_1, s) {
        std::cout << _1->n << " ";
    }
}

-8 -6 -4 -2 0 1 3 5 7 9

こんな感じです。
*bll::_1 < *bll::_2 はデフォルトコンストラクトされないのでsetのコンストラクタに *bll::_1 < *bll::_2 を渡してやらないといけないのがちょっとだけめんどくさいですね。そこで回答者は、setのコンストラクタにこの引数を勝手に渡してやるようにsetを継承することも提案しています。

テンプレート引数にBOOST_TYPEOFとBoost.Lambdaを使うのはおもしろいと思った。