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

にゃははー

はへらー

Boost.Range でも regular が使いたい! - C++ AdC 2013

C++ Advent Calendar 2013 - PARTAKE の12日目です。

もう一個のカレンダーの方で激おことかforkforkとか言ってたら、なんかみんな頑張ってるしカレンダー名に(fork)とか付いてしまってて申し訳ないなーとか思ってたり少しはしているのですが、特にカレンダー書く予定はないです。

ネタを Modularized Boost(GitHubへ移行したリポジトリ)を使用する | イグトランスの頭の中(のかけら) に掻っ攫われてしまったので急遽頑張って考えました。
嘘です特に考えてませんでした。

ところがつい先日会社の同期が Boost.Range に足下掬われていて丁度いいかなと思ってネタにします。


Boost.Range 2.0が広く一般的に普及し、もはや高等教育で指導される程までになりました(なってません、ナムサン!!)が、先人が通ってきた落とし穴については多くは語られてこなかったようです。
Boost.Range 2.0が便利だと思っていたのはいつのことでしょう。人々はもはやfilteredやtransformedだけでは気が済まなくなっています。

そうです。P-stade.Ovenですね。

しかしP-stade.Ovenを導入するのはハードルが高い。卵?ケチャップ?オムレツでも作るのか?
Boost.Build v2で通るのか?わからん。

ということで OvenToBoost ですね。
https://github.com/faithandbrave/OvenToBoost/

しかしBoostはreviewのハードルが高い。とにかく高い。reviewが通らないということではない。
reviewが始まらないのだ。 ※晶さんのコメントがあります。そちらを参照してください。
http://www.boost.org/community/review_schedule.html
これでは新しいライブラリを使うどころではない。

しかしBoostもこの数年で変わった。1.55.0を最後にsvnは終演を迎え、git(github)へと移行したし。
https://github.com/boostorg/

OvenToBoost はgithub上のプロジェクトで、gitは共通の祖先がないbranchもマージできる。
github上ではBoostの各ライブラリは綺麗に分離されて管理、開発されるわけで、つまりOvenToBoost を Boost.Range にマージすることは容易いはず。
Boost.Range にマージすることができれば、そっちを参照するようなsuper-projectを用意するだけで OvenToBoost がマージされたBoostのコードツリーが手に入るということですね。

svnからgitに移る時にディレクトリ構造が割りと変わっているので、OvenToBoost もそれに倣って変更してやればいけるはず。
変更した。 https://github.com/Flast/OvenToBoost

で、後は Boost.Range にマージすればよくて、とりあえず Boost.Range は develop をベースにマージしてみることにした。
https://github.com/Flast/range/tree/oven
ドキュメントはちょっとめんどくなったので、適当に qbk だけマージして html は生成しますた。ドキュメントはそのうちまともに出来るといいな
(ぎっはぶさんのグラフ微妙に変なのなんでなんだろう...

ということで、多分みなさんの手元には https://github.com/boostorg/boost があると思うので、

$ cd boost/libs/range
$ git remote add flast git://github.com/Flast/range.git
$ git fetch flast
$ git checkout flast/oven
$ cd ../../
$ b2 stage
$ sudo b2 install --prefix=/path/to

とかしてみましょう

#define BOOST_RESULT_OF_USE_DECLTYPE
#include <iostream>
#include <array>
#include <cstddef>
#include <boost/algorithm/cxx11/iota.hpp>
#include <boost/range/any_range.hpp>
#include <boost/range/adaptor/taken.hpp>
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/regular_extension/filtered.hpp>

int main()
{
    std::array<int, 20> a;
    boost::algorithm::iota(a, 0);

    boost::any_range<int, boost::forward_traversal_tag, int &, std::ptrdiff_t>
      r = a
          |+ boost::adaptors::filtered([](int v) { return v % 2; })
          |  boost::adaptors::taken(5);

    for (int v : r) { std::cout << v << std::endl; }
}

とかをコンパイルして実行すると

1
3
5
7
9

とか出てきます。ヤッタ!

あ、

#define BOOST_RESULT_OF_USE_DECLTYPE

はn3276 decltypeを持ってるコンパイラなら不要だったと思います。今手元はGCC 4.7.2なので。

std::terminate()

とりあえずこのブランチがあればreviewが入らなくても数年は生きていけそうです。嫌ですreview始まって下さい。
reviewは終わってるので問題なかったです。嫌ですマージして下さい。

なんか最初に同期をネタにするとか言ってましたが、彼が蹴躓いたのは range adaptor に C++11 lambda を投げたところです。
regular ですね。regular operator も使えてます。
正直全然 adaptor 足りないのは不満として残ってはいるけど、OvenToBoost が欲しい一番の理由は regular ですね。

ヨイ!

追記:
Boost.Conversion のjamがタコいのかわからないですが、cast.hppが上手くコピーされないという現象があるっぽいです...
頑張って libs/conversion/include/boost/cast.hpp を引っ張ってくれば通るはず

追記2:
"Boost.Python をビルドしよう" としないとコピーされないヘッダがいくつかあって、それの中にcast.hppが含まれているみたいです...
多分他のライブラリも同じようなものがある気がします...
b2 --without-python でビルドする場合でも、一回すべてのライブラリをビルドしようとした方がいいようです。