Created
June 5, 2010 13:10
-
-
Save niha/426614 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// せつめい | |
// C++ 0x で (T1, T2, ... TN) -> R を T1 -> (T2 -> ... TN)..) -> Ret する curry を実装した。 | |
// tuple に引数を溜めていき、最後に apply を利用して関数を呼び出す。 | |
// decltype は再帰関数のシグネチャには使えないので返値型を計算する type function を書いた。 | |
// enable_if で頑張れば書けそうだけれど(apply 可能かどうか)面倒なのでジェネリックには実装していない。 | |
#include <tuple> | |
#include <type_traits> | |
#include <functional> | |
using namespace std; | |
template <unsigned int N> | |
struct apply_impl { | |
template <typename Fun, typename ...Args, typename ...BoundArgs> | |
static auto impl(Fun fun, tuple<Args...> t, BoundArgs... args) -> decltype(fun(declval<Args>()...)) { | |
return apply_impl<N-1>::impl(fun, t, std::get<N-1>(t), args...); | |
} | |
}; | |
template <> | |
struct apply_impl<0> { | |
template <typename Fun, typename ...Args> | |
static auto impl(Fun fun, tuple<Args...> t, Args... args) -> decltype(fun(args...)) { | |
return fun(args...); | |
} | |
}; | |
template <typename Fun, typename ...Args> | |
auto apply(Fun fun, tuple<Args...> t) -> decltype(fun(declval<Args>()...)) { | |
return apply_impl<sizeof...(Args)>::impl(fun, t); | |
} | |
template <typename Ret, typename Args> | |
struct RetType; | |
template <typename Ret> | |
struct RetType<Ret, tuple<>> { | |
typedef Ret type; | |
}; | |
template <typename Ret, typename ArgsHead, typename ...ArgsTail> | |
struct RetType<Ret, tuple<ArgsHead, ArgsTail...>> { | |
typedef typename RetType<Ret, tuple<ArgsTail...>>::type Partial; | |
typedef function<Partial (ArgsHead)> type; | |
}; | |
template <typename T> | |
struct curry_impl; | |
template <> | |
struct curry_impl<tuple<>> { | |
template <typename Ret, typename ...Args> | |
static auto impl(Ret (*fun)(Args...), tuple<Args...> t) -> Ret { | |
return apply(fun, t); | |
} | |
}; | |
template <typename UnBoundArgsHead, typename ...UnBoundArgsTail> | |
struct curry_impl<tuple<UnBoundArgsHead, UnBoundArgsTail...>> { | |
template <typename Ret, typename ...Args, typename ...BoundArgs> | |
static auto impl(Ret (*fun)(Args...), tuple<BoundArgs...> t) -> typename RetType<Ret, tuple<UnBoundArgsHead, UnBoundArgsTail...>>::type { | |
return [fun, t](UnBoundArgsHead arg){ return curry_impl<tuple<UnBoundArgsTail...>>::impl(fun, tuple_cat(t, make_tuple(arg))); }; | |
} | |
}; | |
template <typename Ret, typename ...Args> | |
auto curry(Ret (*fun)(Args...)) -> typename RetType<Ret, tuple<Args...>>::type { | |
return curry_impl<tuple<Args...>>::impl(fun, make_tuple()); | |
} | |
///////////////////////////////////////// | |
#include <iostream> | |
int f(){ | |
return 0; | |
} | |
int g(int i){ | |
return i; | |
} | |
int h(int i, int j){ | |
return i + j; | |
} | |
int main(){ | |
cout << curry(f) << endl; | |
cout << curry(g)(1) << endl; | |
cout << curry(h)(1)(2) << endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment