overloaded_function, fusedがラムダ式に対応した

ちょっと頑張ってmake_overloadやmake_fusedでラムダ式も扱えるようにしました。

https://github.com/fimbul/shiro/blob/master/shiro/functional/overloaded_function.hpp
https://github.com/fimbul/shiro/blob/master/shiro/tuple/fused.hpp

これで以下のようなコードが書けるようになりました。
かくなる上は関数ポインタ対応か。

#include <shiro/functional.hpp>
#include <shiro/tuple.hpp>
#include <cassert>

int main() {
  constexpr auto f = shiro::make_fused(
      shiro::make_overload(std::plus<int>{}, std::minus<double>{}));
  static_assert(f(1, 2) == 3, "");
  static_assert(f(3.0, 1.0) == 2.0, "");
  static_assert(f(shiro::make_tuple(1, 2)) == 3, "");
  static_assert(f(shiro::make_tuple(3.0, 1.0)) == 2.0, "");

  auto g = shiro::make_fused(
      shiro::make_overload([](auto a, auto b) { return a + b; },
                           [](auto a, auto b, auto c) { return a + b + c; }));
  assert(g(1, 2) == 3);
  assert(g(1, 2, 3) == 6);
  assert(g(shiro::make_tuple(1, 2)) == 3);
  assert(g(shiro::make_tuple(1, 2, 3)) == 6);
}

overloaded_function, fusedを実装した。

実験的なライブラリなので、後々仕様変更などをするかもしれませんが、とりあえずshiro::tupleに対して使えるfusedまで実装しました。現状overloaded_functionが扱えるのは関数オブジェクトだけですが、のちのちboost::overloaded_functionのように関数オブジェクト以外にも対応出来るようにしたいなぁと考えていたりします。あとついでに適当にmake_overloadとmake_fusedも入ってます。

overloaded_function
https://github.com/fimbul/shiro/blob/master/shiro/functional/overloaded_function.hpp
fused
https://github.com/fimbul/shiro/blob/master/shiro/tuple/fused.hpp

これで以下のように書くことが出来るようになりました。

#include <shiro/tuple.hpp>
#include <shiro/functional.hpp>

int main() {
  constexpr shiro::fused<
    shiro::overloaded_function<std::plus<int>, std::minus<double>>
  > f{};

  static_assert(f(1, 2) == 3, "");
  static_assert(f(3.5, 1.5) == 2.0, "");
  static_assert(f(shiro::make_tuple(1, 2)) == 3, "");
  static_assert(f(shiro::make_tuple(3.5, 1.5)) == 2.0, "");
}

index_tuple_catを書いた

typename index_tuple_cat<index_tuple<Indices1...>, index_tuple<Indices2...>, ..., index_tuple<IndicesN...>>::typeがindex_tuple<Indices1..., Indices2..., ..., IndicesN...>となるようなメタ関数を書きました。

https://github.com/fimbul/shiro/blob/master/shiro/utility/index_tuple_cat.hpp

tupleの実装記事の紹介

以下のページで2012年の時点でインデックスを割り振って多重継承するというアプローチが紹介されていたようです。ここまでtupleの実装について丁寧に解説してくれている記事もなかなか無いと思います。もっと早く知りたかった。
http://mitchnull.blogspot.jp/2012/06/c11-tuple-implementation-details-part-1.html

The non-recursive approach

The basic idea behind the non-recursive tuple implementation is that tuple elements are stored in TupleLeaf base classes, but whereas the recursive implementation uses a deep class hierarchy, we'll use multiple-inheritance. In pseudo-code:

template<typename T0, typename T1, ..., typename Tn>
class PseudoTuple : TupleLeaf<0, T0>, TupleLeaf<1, T1>, ..., TupleLeaf<n, Tn> {
...
};

Each leaf has an index, so that each base-class becomes unique even if the types they contain are identical, so we can access the nth element with a simple static_cast:

static_cast<TupleLeaf<0, T0>*>(this);
// ...
static_cast<TupleLeaf<n, Tn>*>(this);

しかし戻り値型を得る為に線形再帰のtuple_elementを使っているので要素アクセスが早いというわけではないみたいです。この点は型をtemplate argument deductionで得る方法の方が優れていますね。

What's Wrong with the For Loop

ユーザコードでループを使う代わりに、ループの役割を分担した高階関数を状況に応じて使い分ける方が良いスタイルだろうという話。

What's Wrong with the For Loop
http://notes-on-haskell.blogspot.jp/2007/02/whats-wrong-with-for-loop.html