可変引数テンプレートのパラメータパックを任意の場所で分解して std::tuple にしたい

## ことの発端

「[Cでよくある非同期関数のコールバック関数でラムダ導入子有りのラムダ式を使えるようにしたい（続き）](https://qiita.com/terukazu/items/a2690cd7ed9bd21b146a)」の振り返りでこんな課題が残っていたのでした。

> パラメータパックの最後の２つを差し替えたいんだけど方法が思いつかなかったので prepare の型が不定になってしまう。

という事で、templateに渡ってくるパラメータパックを分解する方法を考えようと思いました。

## 方針としては

* 最終的にパラメータパックは```std::tuple```で取り扱えば、```std::apply```で関数を呼び出せるので、分解したものは```std::tuple```で良いかな。
* ```std::tuple``` は```std::tuple_cat```で合成できるけど、```std::tuple```を分離させることが困難な気がする。（調べてみたけど、なかなか情報が見つからない）
* となると、パラメータパックの状態で分離するしかなさそうだ。

こんな感じで進めてみました。

## 書いてみた

```cpp:サンプルコード
#include <iostream>
#include <tuple>

template <int N, typename ...ARGS> struct pick;

template <typename ...ARGS> struct pick<0, ARGS...> {
  using types = std::tuple<>;
  using after = std::tuple<ARGS...>;
};

template <typename T1, typename ...ARGS> struct pick<1, T1, ARGS...> {
  using types = std::tuple<T1>;
  using after = std::tuple<ARGS...>;
};

template <typename T1, typename T2, typename ...ARGS> struct pick<2, T1, T2, ARGS...> {
  using types = std::tuple<T1, T2>;
  using after = std::tuple<ARGS...>;
};

template <typename T1, typename T2, typename T3, typename ...ARGS> struct pick<3, T1, T2, T3, ARGS...> {
  using types = std::tuple<T1, T2, T3>;
  using after = std::tuple<ARGS...>;
};

template <typename T1, typename T2, typename T3, typename T4, typename ...ARGS> struct pick<4, T1, T2, T3, T4, ARGS...> {
  using types = std::tuple<T1, T2, T3, T4>;
  using after = std::tuple<ARGS...>;
};

template <typename T1, typename T2, typename T3, typename T4, typename T5, typename ...ARGS> struct pick<5, T1, T2, T3, T4, T5, ARGS...> {
  using types = std::tuple<T1, T2, T3, T4, T5>;
  using after = std::tuple<ARGS...>;
};

template <int N, typename ...ARGS> struct rpick {
  using before  = typename pick<std::tuple_size<std::tuple<ARGS...>>::value - N, ARGS...>::types;
  using types   = typename pick<std::tuple_size<std::tuple<ARGS...>>::value - N, ARGS...>::after;
};

int main(void) {
  using pick_type = pick<2, int, float, void*, char>::types;
  /*  pick_type = std::tuple<int, float> */

  using pick_after = pick<2, int, float, void*, char>::after;
  /*  pick_after = std::tuple<void *, char> */

  using rpick_type = rpick<1, int, float, void*, char>::types;
  /*  rpick_type = std::tuple<char> */

  using rpick_before = rpick<1, int, float, void*, char>::before;
  /*  rpick_type = std::tuple<char> */
}
```

何というか、「```可変引数テンプレート```ってこの手の作業を楽にするためにできた機能じゃないの？」という気もするが、これでいいのか？

## 使い方

パラメータパックの先頭から　N　個を```std::tuple```にする.

```cpp
pick<N, ARGS...>::types;
```

パラメータパックの後ろから　N　個を```std::tuple```にする.

```cpp
rpick<N, ARGS...>::types;
```

そうすると、こんな感じで使えるよになるかと

```cpp
template <typename ...ARGS> struct sample {
  using first = typename pick<1, ARGS...>::types;  /* パラメータパックの最初の１個 */
  using last  = typename rpick<1, ARGS...>::types; /* パラメータパックの最後の１個 */
};
```

## 注意点

サンプルコードではパラメータパックは５個までなので、増えてきたら頑張って追加する。
今度はマクロ作ろうか。。。

## 振り返り

* pickちゅうよりsplitって感じかな？
* というか、boost なんかに便利な「アレ」的なのは無いかな？

## マクロ版もやってみた

```cpp
#include <iostream>
#include <tuple>

template <int N, typename ...ARGS> struct pick;

template <typename ...ARGS> struct pick<0, ARGS...> {
  using types = std::tuple<>;
  using after = std::tuple<ARGS...>;
};

#define __(N, TN, T) \
template <TN, typename ...ARGS> struct pick<N, T, ARGS...> { \
  using types = std::tuple<T>; \
  using after = std::tuple<ARGS...>;\
};

#define _(...) __VA_ARGS__

__( 1, _(typename T1), _(T1))
__( 2, _(typename T1, typename T2), _(T1, T2))
__( 3, _(typename T1, typename T2, typename T3), _(T1, T2, T3))
__( 4, _(typename T1, typename T2, typename T3, typename T4), _(T1, T2, T3, T4))
__( 5, _(typename T1, typename T2, typename T3, typename T4, typename T5), _(T1, T2, T3, T4, T5))
__( 6, _(typename T1, typename T2, typename T3, typename T4, typename T5, typename T6), _(T1, T2, T3, T4, T5, T6))
__( 7, _(typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7), _(T1, T2, T3, T4, T5, T6, T7))
__( 8, _(typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8), _(T1, T2, T3, T4, T5, T6, T7, T8))
__( 9, _(typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9), _(T1, T2, T3, T4, T5, T6, T7, T8, T9))
__(10, _(typename T1, typename T2, typename T3, typename T4, typename T5, typename T6, typename T7, typename T8, typename T9, typename T10), _(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10))

#undef __
#undef _

template <int N, typename ...ARGS> struct rpick {
  using before  = typename pick<std::tuple_size<std::tuple<ARGS...>>::value - N, ARGS...>::types;
  using types   = typename pick<std::tuple_size<std::tuple<ARGS...>>::value - N, ARGS...>::after;
};
```

昔、マクロを多用して魔法のようなプログラムを作っていた人がいたが、メンテナンス性が酷すぎてとても手を入れられない状況になったのがトラウマで、マクロってメリットがある場面もあるけど、反面「罠」を作る場面も多いと思うので、どうにも気が引ける。。。
マクロにスコープ的な考え方が導入されれば良いんだけどなぁ〜（あと push pop 的なのでも良いけど）
というか、こう書いていると、規則性があるし、何となく ```template``` にできんもんかなぁ〜と、考え中。。。

## 神様のお陰でできました（2021/03/08 追記）

神様に教えていただいた再帰テンプレートをやってみようと思ったら、躓きがあったので別記事にしました。

https://qiita.com/terukazu/items/4cdc24894d7604465733