使用C ++ lambda部分应用程序? [英] Partial application with a 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屋!