Boost.Rangeをパイプライン記法のままコンテナに変換

# 全てをパイプライン風に書きたい

たとえば、1以上10以下の整数列……から奇数を取りだして……それぞれ二乗した……列が欲しいとき、Scalaのような関数型言語だとメソッドチェーンでさらっと書けます。やりたい気持ちをそのまま書けるので分かりやすいですね。

```scala
val vec = (1 to 10).
  filter(i => i % 2 != 0).
  map(i => i * i).
  toVector

print(vec.mkString(",")) // 1,9,25,49,81
```

C++でも[Boost.Range](http://www.boost.org/doc/libs/1_57_0/libs/range/doc/html/index.html)を使うと、

```cpp
auto range = boost::irange(1, 10)
  | boost::adaptors::filtered([](int i){ return i % 2 != 0; })
  | boost::adaptors::transformed([](int i){ return i * i; })

for (int i : range) std::cout << i << ","; //  1,9,25,49,81,
```

とパイプライン風に書けます。初めて見ると本当にC++か疑ってしまうような記法ですが、黒魔術もといメタプログラミングを駆使するBoostなので何が出来ても不思議ではありませんね :scream: 

さて、すぐに処理しおえるのであればBoost.Rangeの世界で完結しますが、いったん評価してしまってコンテナに格納したい時があります。そういう時は、コンストラクタ使ったり、

```cpp
std::vector<int> vec(std::begin(range), std::end(range));
```

コピー関数使ったり、

```cpp
std::vector<int> vec;
boost::copy(range, std::back_inserter(vec));
```

する必要があります。どうせならコンテナに変換するところまでパイプライン風に書きたいものです。

# Boost + Oven = :heart_eyes: 

高橋晶さんの[Boost.Range拡張ライブラリ](https://github.com/faithandbrave/OvenToBoost)を使うと、コンテナ変換もできるそうです。すごい！
これは現在[Boost Formal Review Schedule](http://www.boost.org/community/review_schedule.html)に載っていて、マージ待ちのようです。
boost単体で使えるようになると、とても嬉しいですね。

```cpp
std::vector<int> vec = boost::irange(1, 10)
  | boost::adaptors::filtered([](int i){ return i % 2 != 0; })
  | boost::adaptors::transformed([](int i){ return i * i; })
  | boost::as_container; // !?
```

``` boost::as_container ```は、[PStade.Oven](http://p-stade.sourceforge.net/oven/doc/html/index.html)というライブラリの``` oven::copied ```を移植したものだそうです。
ちなみにPStade.Ovenの作者 @okomok さんは、Scalaのメタプログラミングライブラリsingなども作っています。すごい……！

関連記事：[型に数値を埋めこんでみよう](http://qiita.com/piyo7/items/5df3ad7e53216df5f65f)

# 自前で作ってみる

実は``` boost::as_container ```を見つける前に、似たようなものを試行錯誤して作ってみたのですが、参考にした記事のうち「[C++ で拡張メソッドできるよ](http://faithandbrave.hateblo.jp/entry/20080529/1212051468)」「[initializer_list(仮)の前準備 container_convertor](http://faithandbrave.hateblo.jp/entry/20080222/1203670672)」が高橋晶さんのブログだったので、先人の軌跡をなぞっていただけでした :open_mouth: 
でも、せっかくなので、自前で作った方も書いておきます。

まず``` boost::adaptors ```の実装を覗きながら、``` std::vector ```に変換する``` to_vec ```を作りました。
``` to_vec ```は、自前の``` operator | ```を呼びだすの単なるタグなのですが、これは[tag dispatching](http://www.boost.org/community/generic_programming.html#tag_dispatching)と呼ばれる手法とのことです。

```cpp
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/irange.hpp>
#include <iterator>
#include <vector>

// 自前のoperator|をオーバーロードで呼びだすためのタグ
struct ToVector {};
ToVector to_vec = ToVector();

template<
  typename Range, // 制約：value_typeが定義されていること、std::beginとstd::end呼べること
  typename T = typename Range::value_type
>
std::vector<T> operator | (
  const Range& range,
  ToVector // タグ
) {
  return std::vector<T>(std::begin(range), std::end(range));
}

int main() {
  std::vector<int> vec = boost::irange(1, 10)
    | boost::adaptors::filtered([](int n){ return n % 2 != 0; })
    | boost::adaptors::transformed([](int n){ return n * n; })
    | to_vec; // できた！

  return 0;
}
```
http://melpon.org/wandbox/permlink/1WhNl4PGSPqHdsrU

同様に、合計したり平均取ったりするreduce関数のタグも作れます。

さて、これで``` boost::as_container ```と同等の機能が実現……できていないですね。
``` boost::as_container ```の凄いところは、変換する具体的なコンテナを``` std::vector ```に限らず``` std::list ```や``` std::deque ```など代入先の型で選べるところです。
これを実現するために、暗黙の型変換を行う補助クラスを作りました。

```cpp
#include <boost/range/adaptor/filtered.hpp>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/irange.hpp>
#include <iterator>
#include <vector>

// 暗黙の型変換クラス
template <typename Range>
class RangeConverter {
  const Range& range_;

public:
  RangeConverter(const Range& range): range_(range) {}

  // 暗黙の型変換関数
  template <
    typename Target // 制約：先頭と末尾のイテレーターによるコンスラクタがあること
  >
  operator Target() const {
    return Target(std::begin(range_), std::end(range_));
  }
};

struct ToContainer {};
ToContainer to_cont = ToContainer();

template<
  typename Range,
  typename T = typename Range::value_type
>
RangeConverter<Range> operator | (
  const Range& range,
  ToContainer
) {
  return RangeConverter<Range>(range); // 具体的なコンテナへの変換はRangeConverterに委ねる
}

int main() {
  std::vector<int> vec = boost::irange(1, 10)
    | boost::adaptors::filtered([](int n){ return n % 2 != 0; })
    | boost::adaptors::transformed([](int n){ return n * n; })
    | to_cont; // できた……！

  return 0;
}
```
http://melpon.org/wandbox/permlink/wFj5ZFOCUcvaos5g