使用C ++ lambda部分应用程序? [英] Partial application with a C++ lambda?

查看:162
本文介绍了使用C ++ lambda部分应用程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

编辑:我在下面使用curry,但已被通知这是部分应用程序。

I use curry below, but have been informed this is instead partial application.

我一直在想办法如何写一个curry函数在C ++中,我真的想出来了!

I've been trying to figure out how one would write a curry function in C++, and i actually figured it out!

#include <stdio.h>
#include <functional>

template< class Ret, class Arg1, class ...Args >
auto curry(  Ret f(Arg1,Args...), Arg1 arg )
    -> std::function< Ret(Args...) >
{
    return [=]( Args ...args ) { return f( arg, args... ); };
}

我也为lambdas写了一个版本。

And i wrote a version for lambdas, too.

template< class Ret, class Arg1, class ...Args >
auto curry(  const std::function<Ret(Arg1,Args...)>& f, Arg1 arg )
    -> std::function< Ret(Args...) >
{
    return [=]( Args ...args ) { return f( arg, args... ); };
}

测试:

int f( int x, int y )
{
    return x + y;
}

int main()
{
    auto f5 = curry( f, 5 );
    auto g2 = curry( std::function<int(int,int)>([](int x, int y){ return x*y; }), 2 );
    printf("%d\n",f5(3));
    printf("%d\n",g2(3));
}

auto g2 = [](int y){ return 2*y; };

更短。但由于目的是有一个真正的通用和方便的咖喱函数,我可以(1)写一个更好的函数或(2)不知何故我的lambda隐式构造std ::函数?我担心当前版本违反最小惊喜的规则,当f不是一个自由函数。特别恼人的是没有make_function或类似类型的功能,我知道似乎存在。真的,我的理想的解决方案只是一个调用std :: bind,但我不知道如何使用它与可变参数模板。

Much shorter. But since the intent is to have a really generic and convenient curry function, could i either (1) write a better function or (2) somehow my lambda to implicitly construct an std::function? I fear the current version violates the rule of least surprise when f is not a free function. Especially annoying is how no make_function or similar-type function that i know of seems to exist. Really, my ideal solution would just be a call to std::bind, but i'm not sure how to use it with variadic templates.

PS:请,但我会安定,如果没有别的。

PS: No boost, please, but i'll settle if nothing else.

编辑:我已经知道std :: bind。我不会写这个函数,如果std :: bind做了我想要的最好的语法。

I already know about std::bind. I wouldn't be writing this function if std::bind did exactly what i wanted with the best syntax. This should be more of a special case where it only binds the first element.

正如我所说的,我的理想解决方案应该使用绑定,但是它只能绑定第一个元素。如果我想使用,我会使用。

As i said, my ideal solution should use bind, but if i wanted to use that, i'd use that.

推荐答案

很多人提供的例子,使用助手类来做任何他们做的事情。我意识到当你这样做的时候写作变得很不方便!

A lot of the examples people provided and that i saw elsewhere used helper classes to do whatever they did. I realized this becomes trivial to write when you do that!

#include <utility> // for declval
#include <array>
#include <cstdio>

using namespace std;

template< class F, class Arg >
struct PartialApplication
{
    F f;
    Arg arg;

    constexpr PartialApplication( F&& f, Arg&& arg )
        : f(forward<F>(f)), arg(forward<Arg>(arg))
    {
    }

    /* 
     * The return type of F only gets deduced based on the number of arguments
     * supplied. PartialApplication otherwise has no idea whether f takes 1 or 10 args.
     */
    template< class ... Args >
    constexpr auto operator() ( Args&& ...args )
        -> decltype( f(arg,declval<Args>()...) )
    {
        return f( arg, forward<Args>(args)... );
    }
};

template< class F, class A >
constexpr PartialApplication<F,A> partial( F&& f, A&& a )
{
    return PartialApplication<F,A>( forward<F>(f), forward<A>(a) );
}

/* Recursively apply for multiple arguments. */
template< class F, class A, class B >
constexpr auto partial( F&& f, A&& a, B&& b )
    -> decltype( partial(partial(declval<F>(),declval<A>()),
                         declval<B>()) )
{
    return partial( partial(forward<F>(f),forward<A>(a)), forward<B>(b) );
}

/* Allow n-ary application. */
template< class F, class A, class B, class ...C >
constexpr auto partial( F&& f, A&& a, B&& b, C&& ...c )
    -> decltype( partial(partial(declval<F>(),declval<A>()),
                         declval<B>(),declval<C>()...) )
{
    return partial( partial(forward<F>(f),forward<A>(a)), 
                    forward<B>(b), forward<C>(c)... );
}

int times(int x,int y) { return x*y; }

int main()
{
    printf( "5 * 2 = %d\n", partial(times,5)(2) );
    printf( "5 * 2 = %d\n", partial(times,5,2)() );
}

这篇关于使用C ++ lambda部分应用程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆