«Глубокая» функция каррирования в C ++ с использованием шаблонного метапрограммирования
Я только что придумал (еще одну!) Реализацию функции каррирования в C ++ с использованием шаблонного метапрограммирования. (Я почти уверен, что другие реализации лучше / более полны, чем моя, но я делаю это для целей обучения, в случае, если я думаю, что изобретать колесо оправдано.)
Моя реализация карринг-функции, включая тестовый пример, следующая:
<code>#include <iostream> #include <functional> template <typename> class curry; template <typename _Res> class curry< _Res() > { public: typedef std::function< _Res() > _Fun; typedef _Res _Ret; private: _Fun _fun; public: explicit curry (_Fun fun) : _fun(fun) { } operator _Ret () { return _fun(); } }; template <typename _Res, typename _Arg, typename... _Args> class curry< _Res(_Arg, _Args...) > { public: typedef std::function< _Res(_Arg, _Args...) > _Fun; typedef curry< _Res(_Args...) > _Ret; private: class apply { private: _Fun _fun; _Arg _arg; public: apply (_Fun fun, _Arg arg) : _fun(fun), _arg(arg) { } _Res operator() (_Args... args) { return _fun(_arg, args...); } }; private: _Fun _fun; public: explicit curry (_Fun fun) : _fun(fun) { } _Ret operator() (_Arg arg) { return _Ret(apply(_fun, arg)); } }; int main () { auto plus_xy = curry<int(int,int)>(std::plus<int>()); auto plus_2x = plus_xy(2); auto plus_24 = plus_2x(4); std::cout << plus_24 << std::endl; return 0; } </code>
Эта функция каррирования является «мелкой», в следующем смысле: если оригиналstd::function
подпись ...
<code>(arg1, arg2, arg3...) -> res </code>
Тогда сигнатура карри функции ...
<code>arg1 -> arg2 -> arg3 -> ... -> res </code>
Однако, если любой из аргументов или сам тип возвращаемого значения может быть каррирован, они не каррируются. Например, если оригиналstd::function
подпись ...
<code>(((arg1, arg2) -> tmp), arg3) -> res </code>
Тогда сигнатура функции карри будет ...
<code>((arg1, arg2) -> tmp) -> arg3 -> res </code>
Вместо...
<code>(arg1 -> arg2 -> tmp) -> arg3 -> res </code>
Что я и хочу. Поэтому я хотел бы иметь "глубокую" карринг реализации. Кто-нибудь знает, как я мог это написать?
@vhallac:
Это та функция, которая должна быть передана в конструкторcurry<int(int(int,int),int)>
:
<code>int test(std::function<int(int,int)> f, int x) { return f(3, 4) * x; } </code>
Тогда нужно уметь делать следующее:
<code>auto func_xy = curry<int(int(int,int),int)>(test); auto plus_xy = curry<int(int,int)>(std::plus<int>()); auto func_px = func_xy(plus_xy); auto func_p5 = func_px(5); std::cout << func_p5 << std::endl; </code>