Funkcja „Deep” currying w C ++ za pomocą szablonowego metaprogramowania

Właśnie wymyśliłem (jeszcze jedną!) Implementację funkcji currying w C ++ za pomocą szablonowego metaprogramowania. (Jestem prawie pewien, że inne implementacje są lepsze / bardziej kompletne niż moje, ale robię to w celach edukacyjnych, w przypadku, gdy myślę, że ponowne wymyślenie koła jest uzasadnione).

Moja funkcja polegająca na wprowadzeniu curry, w tym przypadku testowego, jest następująca:

<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>

Ta funkcja currying implementacji jest „płytka” w następującym znaczeniu: Jeśli oryginałstd::functionpodpis jest ...

<code>(arg1, arg2, arg3...) -> res
</code>

Wówczas podpis funkcji kuratora to ...

<code>arg1 -> arg2 -> arg3 -> ... -> res
</code>

Jednakże, jeśli którykolwiek z argumentów lub sam typ powrotu może zostać poddany curry, nie zostanie on zaklinowany. Na przykład, jeśli oryginałstd::functionpodpis jest ...

<code>(((arg1, arg2) -> tmp), arg3) -> res
</code>

Wtedy podpis funkcji curried będzie ...

<code>((arg1, arg2) -> tmp) -> arg3 -> res
</code>

Zamiast...

<code>(arg1 -> arg2 -> tmp) -> arg3 -> res
</code>

Tego właśnie chcę. Chciałbym więc mieć „głęboką” currying implementację. Czy ktoś wie, jak mogę to napisać?

@vhallac:

Jest to rodzaj funkcji, którą należy przekazać konstruktorowicurry<int(int(int,int),int)>:

<code>int test(std::function<int(int,int)> f, int x)
{ return f(3, 4) * x; }
</code>

Wtedy powinno być możliwe wykonanie następujących czynności:

<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>

questionAnswers(1)

yourAnswerToTheQuestion