引数の数も型も未知の関数に、自動で引数を付けて呼び出す。

[前回](http://qiita.com/s-wakaba/items/bef3fae03e1294725fea)の続き。
前回は、関数の引数の型は`int`で固定していたが、これも可変にしたい。

ただ、無尽蔵に対応はできないので、とりあえず`int`と`double`を自動判別して、`double`の時は`0.5`を加えたものを引数にする。

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

double func3(double n1, int n2, int n3) {
    std::cout << n1 << '+' << n2 << '+' << n3 << '=' << std::flush;
    return n1+n2+n3;
}
double func2(int n1, double n2) {
    std::cout << n1 << '+' << n2 << '=' << std::flush;
    return n1+n2;
}
double func1(double n1) {
    std::cout << n1 << '=' << std::flush;
    return n1;
}
double func0(void) {
    return 0;
}


template<typename T> constexpr T getarg(int);
template<> constexpr double getarg<double>(int n) { return n+0.5; }
template<> constexpr int getarg<int>(int n) { return n; }


template<int N, typename Types, typename Func, typename ...Args>
auto add_steparg(typename std::enable_if<!N>::type*, Func func, Args... args) {
    return func(args...);
}

template<int N, typename Types, typename Func, typename ...Args>
auto add_steparg(typename std::enable_if<N>::type*, Func func, Args... args) {
    typedef typename std::tuple_element<N-1, Types>::type T;
    constexpr auto arg = getarg<T>(N);
    return add_steparg<N-1, Types>(0, func, arg, args...);
}

template<typename Ret, typename ...Args>
Ret stepargs(Ret (*func)(Args...)) {
    return add_steparg<sizeof...(Args), std::tuple<Args...>>(0, func);
}

int main(void){
    std::cout << stepargs(func3) << std::endl;
    std::cout << stepargs(func2) << std::endl;
    std::cout << stepargs(func1) << std::endl;
    std::cout << stepargs(func0) << std::endl;
    return 0;
}
```

実行結果は、

```text
1.5+2+3=6.5
1+2.5=3.5
1.5=1.5
0
```

* `std::tuple<Args...>`を、テンプレート引数`Types`を使って、関数引数の型を伝搬させるためだけに使う。
* `N`番目のタプルの型は、`typename std::tuple_element<N, Types>::type`でコンパイル時に取得できる。
* 関数の引数の型が取得できれば、それに応じた変換関数`template<T> T getarg(int)`を呼ぶ。
* 呼ばれる変換関数と、その引数、さらに計算結果は全てコンパイル時に決定できるので、`constexpr`を付けておく。
* これで実行時には定数引数による関数呼び出し以外することは無くなる。
* `<type_traits>`の`is_xxxx`系関数を駆使すれば、もっといろいろできそう。

タプルにアクセスするのが後ろからなのが気持ち悪ければ、

```cpp
template<int N, typename Types, typename Func, typename ...Args>
auto add_steparg(typename std::enable_if<N>::type*, Func func, Args... args) {
    constexpr auto M = std::tuple_size<Types>::value - N;
    typedef typename std::tuple_element<M, Types>::type T;
    constexpr auto arg = getarg<T>(M+1);
    return add_steparg<N-1, Types>(0, func, args..., arg);
}
```

余談:下みたいに定義されてたらよかったのに、と思った。

```cpp
using T = tuple<C1, C2, C3, C4>;
static_assert<is_same<T::first_type, C1>>();
static_assert<is_same<T::last_type, C4>>();
static_assert<is_same<T::tuple_after_first, tuple<C2, C3, C4>>>();
static_assert<is_same<T::tuple_before_last, tuple<C1, C2, C3>>>();
```

おしまい。

追記
---

前回と同じく、`if constexpr`が使えれば、下記のようにも書ける模様。
醜い`add_steparg`の第一引数がいらないので、こちらのほうが素敵。

```cpp
template<int N, typename Types, typename Ret, typename Func, typename ...Args>
Ret add_steparg(Func func, Args... args) {
    if constexpr(N) {
        using T = typename std::tuple_element<N-1, Types>::type;
        constexpr auto arg = getarg<T>(N);
        return add_steparg<N-1, Types, Ret>(func, arg, args...);
    } else {
        return func(args...);
    }
}

template<typename Ret, typename ...Args>
Ret stepargs(Ret (*func)(Args...)) {
    return add_steparg<sizeof...(Args), std::tuple<Args...>, Ret>(func);
}
```