I'm trying to write a simple function to convert a std::function<> object while binding the last parameter(s). That's what I've got:
template<typename R, typename Bind, typename ...Args> std::function<R (Args...)> bindParameter (std::function<R (Args..., Bind)> f, Bind b)
{
return [f, b] (Args... args) -> R { return f (args..., b); };
}
And that's how I'd like to use it:
int blub (int a, int b)
{
return a * b;
}
// ...
int main ()
{
std::function<int (int, int)> f1 (blub);
// doesn't work
std::function<int (int)> f2 = bindParameter (f1, 21);
// works
std::function<int (int)> f3 = bindParameter<int, int, int> (f1, 21);
return f2 (2);
}
... so that in this example the main function should return 42. The problem is, that gcc (4.6) doesn't seem to infer the types of the template parameters correctly, the first version produces the following errors:
test.cpp:35:58: error: no matching function for call to 'bindParameter(std::function<int(int, int)>&, int)'
test.cpp:35:58: note: candidate is:
test.cpp:21:82: note: template<class R, class Bind, class ... Args> std::function<R(Args ...)> bindParameter(std::function<R(Args ..., Bind)>, Bind)
But in my opinion the parameters are obvious. Or is this kind of type inference not covered by the standard or not yet implemented in gcc?
You can't use std::function as a deduced parameter of a function template. Deduction can't work in this fashion as there are no rules to match int(*)(int, int) to std::function<int(int, int)>. (Consider also that for any std::function<Signature> there is a constructor accepting int(*)(int, int), even if in most cases this results in an error when instantiated.)
It's problematic to detect the signature of functor in the general case. Even KennyTM's solution has limitations: it detects the signature of monomorphic functors and function-like things, but won't work for polymorphic functors (e.g. with overloaded operator()) or functors with surrogate call functions (even in the monomorphic case).
It is however possible to completely sidestep the issue of detecting the signature thanks to decltype (or equivalently, std::result_of), and I would recommend doing so. Hence, a variant on KennyTM's answer:
template<typename Functor, typename Bound>
struct bind_last_type {
Functor functor;
Bound bound;
template<typename... Args>
auto operator()(Args&&... args)
-> typename std::result_of<Functor&(Args..., Bound)>::type
// equivalent:
// -> decltype( functor(std::forward<Args>(args)..., std::move(bound)) )
{ return functor(std::forward<Args>(args)..., std::move(bound)); }
};
template<typename Functor, typename Bound>
bind_last_type<
typename std::decay<Functor>::type
, typename std::decay<Bound>::type
>
bind_last(Functor&& functor, Bound&& bound)
{ return { std::forward<Functor>(functor), std::forward<Bound>(bound) }; }
Not sure about the inference, but it works if I just define a templated function object.
template <typename FType, typename LastArgType>
struct BindLastHelper
{
FType _f;
LastArgType _last_arg;
template <typename... Args>
typename utils::function_traits<FType>::result_type
operator()(Args&&... args) const
{
return _f(std::forward<Args>(args)..., _last_arg);
}
};
template<typename FType, typename LastArgType>
BindLastHelper<FType, LastArgType> bindParameter (FType f, LastArgType b)
{
return BindLastHelper<FType, LastArgType>{f, b};
}
Note:
utils::function_traits is taken from https://github.com/kennytm/utils/blob/master/traits.hpp. std::result_of cannot be used because you are not passing a function pointer.
Proof of concept: http://ideone.com/ux7YY (here for simplicity I just redefined result_of.)
Related
template<class Fn, class ...Args>
class func_class<Fn(Args...)> // Do not know what to do here
{
typedef typename result_of<Fn(Args...)>::type mytype;
std::function<mytype(Args...)> func_;
std::tuple<Args...> tuple1;
public:
func_class(Fn&& func_in, Args&& ...args)
{
func_ = func_in;
tuple1 = make_tuple(args...);
}
mytype
exe ()
{
mytype ret;
ret = apply(func_, tuple1);
return ret;
}
};
int func(int a) {return a;}
int main () {
// return type of "func" can be deduced by "result_of<decltype(func)&(int)>::type"
// And result_of is declared as "result_of<Fn(Args...)>"
// Want func_class to have the same interface
func_class<decltype(func)&(int)> fc; // Want to declare a object like this
fc.exe();
}
The code is like above. Return type of func can be deduced by result_of<decltype(func)&(int)>::type. And result_of is declared as result_of<Fn(Args...)>.
Want func_class to have the same interface as result_of.
The compiler complains like:
test.cpp:211:7: error: 'func_class' is not a class template
What can I do?
Thank you in advance.
template<class Sig>
struct bob;
template<class R, class...Args>
struct bob<R(Args...)>{
//...
};
specialization.
Uses of bob that fail to pattern match will give compile-time errors.
As a note, using R(Args...) syntax when R is not a return value and Args... are not arguments will lead to unexpected quirks, because of how function argument and return value types are modified by the C/C++ language.
This is why std::result_of<F(Args...)> is deprecated and replaced with std::invoke_result<F, Args...>.
R(Args...) is appropriately used in std::function, because Args... are function arguments, and R is an actual return value, to function<A(Args...)>::operator().
I'm writing my own std::async analogue (has to work back to Intel13/gcc 4.4 STL), and this works fine:
template <typename Func, typename ...Args>
struct return_value {
template <typename T>
using decayed = typename std::decay<T>::type;
using type = typename std::result_of<decayed<Func>(decayed<Args>...)>::type;
};
template <typename Func, typename ...Args>
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
return func(args...);
}
void run(int a, double b) {
printf("a: %i b: %f\n", a, b);
}
int main() {
async(run, 1, 3.14);
}
But if I add an overload for run:
void run() {
printf("no args\n");
}
Then it can't properly resolve:
<source>: In function 'int main()':
<source>:27:23: error: no matching function for call to 'async(<unresolved overloaded function type>, int, double)'
async(run, 1, 3.14);
^
<source>:14:43: note: candidate: 'template<class Func, class ... Args> typename return_value<Func, Args>::type async(Func&&, Args&& ...)'
typename return_value<Func,Args...>::type async(Func &&func, Args&&... args) {
^~~~~
<source>:14:43: note: template argument deduction/substitution failed:
<source>:27:23: note: couldn't deduce template parameter 'Func'
async(run, 1, 3.14);
^
Compiler returned: 1
How can I take a function as a template parameter and properly deduce the overload given the arguments?
I personally don't see a way to disambiguate overloads unless you know the return type. You could assume return type void most common and to this then: (I am simplifying your example for brevity)
template <class F, class... Args>
auto async(F f, Args... args)
{
return f(args...);
}
template <class... Args>
auto async(void (*f)(Args...), Args... args)
{
return f(args...);
}
void run();
void run(int, double);
auto test()
{
async(run); // calls run();
async(run, 1, 2.); // calls run(int, double);
}
This does seem kind of fishy and confusing to the user. Why does it work when the function passed returns void and it doesn't if it returns int? So I don't recommend it.
So really the only thing you could do is let it in the hands of the user to figure it out.
So some solutions for the caller of your function:
The good (and ugly) old way: use cast to disambiguate the overload:
async(static_cast<int(*)(int, double)>(run), 1, 2.);
I personally don't like this approach at all. I don't like the verbosity of it and most of all I don't like that I have to be explicit about something that should really be implicit.
The lambda way
async([] { return run(1, 2.); });
I like this. It's not half bad. Still a little bit verbose, but way way better than other alternatives.
The macro way
Yes, macros, in C++. Without further ado, there it is (perfect forwarding omitted for brevity):
#define OVERLOAD(foo) [] (auto... args) { return foo(args...); }
async(OVERLOAD(run), 1, 2.);
I am not going to comment on this one. I leave each and every one of you to judge this macro.
I'm trying to create template functor, which will take as arguments object and member function with any number of parameters. I can't figure out how to write the code correctly with templates.
template<typename ItemT,
class T,
typename ...Args>
struct Builder
{
ItemT operator()(T& object, ItemT (T::*method)(Args...), Args && ... args)
{
return (object.*method)(std::forward<Args>(args)...);
}
};
struct Object
{
int method(int, int, int) { return 4; }
};
int main()
{
Object obj;
Builder<int, Object>()(obj, &Object::method); // Error here
}
If I make Object::method with no parameters - code compiles. But with parameters - no.
Severity Code Description Project File Line Suppression State
Error C2664 'int Builder::operator ()(T &,ItemT (__thiscall Object::* )(void))': cannot convert argument 2 from 'int (__thiscall Object::* )(int,int,int)' to 'int (__thiscall Object::* )(void)' drafts c:\drafts\main.cpp 139
Assuming you don't want to change the current definition of Builder, this is how you need to instantiate it:
Builder<int, Object, int, int, int>()(obj, &Object::method, 0, 0, 0);
// ^ ^ ^^^^^^^^^^^^^ ^^^^^^^
// ItemT | | |
// T Args... args...
The args... parameter expansion in the operator() call must match the TArgs... pack passed to Builder itself.
wandbox example
Here's an alternative less strict design:
template<typename T>
struct Builder
{
template <typename TFnPtr, typename... Args>
auto operator()(T& object, TFnPtr method, Args && ... args)
{
return (object.*method)(std::forward<Args>(args)...);
}
};
The above Builder can be used like this:
int main()
{
Object obj;
Builder<Object>()(obj, &Object::method, 0, 0, 0);
}
In this case the type of member function pointer is deduced through TFnPtr and not constrained to any particular set of parameters. The variadic parameters are not part of Builder anymore - they're part of Builder::operator(), so they can be deduced and forwarded to (object.*method).
wandbox example
You can avoid templating on Builder altogether and solely rely on template argument deduction:
struct Builder {
template <typename Obj, typename R, typename ... FArgs, typename ... Args>
R operator()(Obj& obj, R (Obj::*fn)(FArgs...), Args&&... args) {
return (obj.*fn)(std::forward<Args>(args)...);
}
};
I chose to use two parameter packs to allow perfect forwarding: the value categories of the operator() call do not necessarily match the targeted method. This also allows for implicit conversion of arguments when applying the member function pointer. Note that this implementation will not match const methods of Obj.
You can of course relax it a bit using auto return type (C++14) or trailing return type (C++11). Since Vittorio's answer already presented you the C++14 way, I'll tackle the latter. The operator() then becomes:
template <typename Obj, typename FnPtr, typename ... Args>
auto operator()(Obj& obj, FnPtr fn, Args&&... args)
-> decltype((obj.*fn)(std::forward<Args>(args)...)) {
return (obj.*fn)(std::forward<Args>(args)...);
}
Then, usage will simply be:
Object obj;
Builder()(obj, &Object::method, 0, 0, 0);
live demo on Coliru.
Given the following code(taken from here):
#include <cstddef>
#include <type_traits>
#include <tuple>
#include <iostream>
#include <utility>
#include <functional>
template<typename ... Fs>
struct compose_impl
{
compose_impl(Fs&& ... fs) : functionTuple(std::forward_as_tuple(fs ...)) {}
template<size_t N, typename ... Ts>
auto apply(std::integral_constant<size_t, N>, Ts&& ... ts) const
{
return apply(std::integral_constant<size_t, N - 1>(), std::get<N> (functionTuple)(std::forward<Ts>(ts)...));
}
template<typename ... Ts>
auto apply(std::integral_constant<size_t, 0>, Ts&& ... ts) const
{
return std::get<0>(functionTuple)(std::forward<Ts>(ts)...);
}
template<typename ... Ts>
auto operator()(Ts&& ... ts) const
{
return apply(std::integral_constant<size_t, sizeof ... (Fs) - 1>(), std::forward<Ts>(ts)...);
}
std::tuple<Fs ...> functionTuple;
};
template<typename ... Fs>
auto compose(Fs&& ... fs)
{
return compose_impl<Fs ...>(std::forward<Fs>(fs) ...);
}
int main ()
{
auto f1 = [](std::pair<double,double> p) {return p.first + p.second; };
auto f2 = [](double x) {return std::make_pair(x, x + 1.0); };
auto f3 = [](double x, double y) {return x*y; };
auto g = compose(f1, f2, f3);
std::cout << g(2.0, 3.0) << std::endl; //prints '13', evaluated as (2*3) + ((2*3)+1)
return 0;
}
The code above works in C++14. I'm having some trouble making it work for C++11. I tried to properly provide the return types for the function templates involved but without much success e.g.:
template<typename... Fs>
struct compose_impl
{
compose_impl(Fs&&... fs) : func_tup(std::forward_as_tuple(fs...)) {}
template<size_t N, typename... Ts>
auto apply(std::integral_constant<size_t, N>, Ts&&... ts) const -> decltype(std::declval<typename std::tuple_element<N, std::tuple<Fs...>>::type>()(std::forward<Ts>(ts)...))
// -- option 2. decltype(apply(std::integral_constant<size_t, N - 1>(), std::declval<typename std::tuple_element<N, std::tuple<Fs...>>::type>()(std::forward<Ts>(ts)...)))
{
return apply(std::integral_constant<size_t, N - 1>(), std::get<N>(func_tup)(std::forward<Ts>(ts)...));
}
using func_type = typename std::tuple_element<0, std::tuple<Fs...>>::type;
template<typename... Ts>
auto apply(std::integral_constant<size_t, 0>, Ts&&... ts) const -> decltype(std::declval<func_type>()(std::forward<Ts>(ts)...))
{
return std::get<0>(func_tup)(std::forward<Ts>(ts)...);
}
template<typename... Ts>
auto operator()(Ts&&... ts) const -> decltype(std::declval<func_type>()(std::forward<Ts>(ts)...))
// -- option 2. decltype(apply(std::integral_constant<size_t, sizeof...(Fs) - 1>(), std::forward<Ts>(ts)...))
{
return apply(std::integral_constant<size_t, sizeof...(Fs) - 1>(), std::forward<Ts>(ts)...);
}
std::tuple<Fs...> func_tup;
};
template<typename... Fs>
auto compose(Fs&&... fs) -> decltype(compose_impl<Fs...>(std::forward<Fs>(fs)...))
{
return compose_impl<Fs...>(std::forward<Fs>(fs)...);
}
For the above clang(3.5.0) gives me the following error:
func_compose.cpp:79:18: error: no matching function for call to object of type 'compose_impl<(lambda at func_compose.cpp:65:15) &, (lambda at func_compose.cpp:67:15) &,
(lambda at func_compose.cpp:68:15) &>'
std::cout << g(2.0, 3.0) << std::endl; //prints '13', evaluated as (2*3) + ((2*3)+1)
^
func_compose.cpp:31:10: note: candidate template ignored: substitution failure [with Ts = <double, double>]: no matching function for call to object of type
'(lambda at func_compose.cpp:65:15)'
auto operator()(Ts&&... ts) /*const*/ -> decltype(std::declval<func_type>()(std::forward<Ts>(ts)...))
^ ~~~
1 error generated.
If I try "option 2." I get pretty much the same error.
Apart from the fact that it looks very verbose I also cannot seem to get it right. Could anyone provide some insight in what am I doing wrong?
Is there any simpler way to provide the return types?
The error message for your first option is due to the fact that in
std::declval<func_type>()(std::forward<Ts>(ts)...)
you're trying to call the f1 functor with two arguments of type double (the ones passed to operator()), but it takes a std::pair (func_type refers to the type of the first functor in the tuple).
Regarding option 2, the reason it doesn't compile is that the trailing return type is part of the function declarator and the function is not considered declared until the end of the declarator has been seen, so you can't use decltype(apply(...)) in the trailing return type of the first declaration of apply.
I'm sure you're now very happy to know why your code doesn't compile, but I guess you'd be even happier if you had a working solution.
I think there's an essential fact that needs to be clarified first: all specializations of the apply and operator() templates in compose_impl have the same return type - the return type of the first functor, f1 in this case.
There are several ways to get that type, but a quick hack is the following:
#include <cstddef>
#include <type_traits>
#include <tuple>
#include <iostream>
#include <utility>
#include <functional>
template<typename> struct ret_hlp;
template<typename F, typename R, typename... Args> struct ret_hlp<R (F::*)(Args...) const>
{
using type = R;
};
template<typename F, typename R, typename... Args> struct ret_hlp<R (F::*)(Args...)>
{
using type = R;
};
template<typename ... Fs>
struct compose_impl
{
compose_impl(Fs&& ... fs) : functionTuple(std::forward_as_tuple(fs ...)) {}
using f1_type = typename std::remove_reference<typename std::tuple_element<0, std::tuple<Fs...>>::type>::type;
using ret_type = typename ret_hlp<decltype(&f1_type::operator())>::type;
template<size_t N, typename ... Ts>
ret_type apply(std::integral_constant<size_t, N>, Ts&& ... ts) const
{
return apply(std::integral_constant<size_t, N - 1>(), std::get<N> (functionTuple)(std::forward<Ts>(ts)...));
}
template<typename ... Ts>
ret_type apply(std::integral_constant<size_t, 0>, Ts&& ... ts) const
{
return std::get<0>(functionTuple)(std::forward<Ts>(ts)...);
}
template<typename ... Ts>
ret_type operator()(Ts&& ... ts) const
{
return apply(std::integral_constant<size_t, sizeof ... (Fs) - 1>(), std::forward<Ts>(ts)...);
}
std::tuple<Fs ...> functionTuple;
};
template<typename ... Fs>
compose_impl<Fs ...> compose(Fs&& ... fs)
{
return compose_impl<Fs ...>(std::forward<Fs>(fs) ...);
}
int main ()
{
auto f1 = [](std::pair<double,double> p) {return p.first + p.second; };
auto f2 = [](double x) {return std::make_pair(x, x + 1.0); };
auto f3 = [](double x, double y) {return x*y; };
auto g = compose(f1, f2, f3);
std::cout << g(2.0, 3.0) << std::endl; //prints '13', evaluated as (2*3) + ((2*3)+1)
return 0;
}
Notes:
It compiles and works on GCC 4.9.1 and Clang 3.5.0 in C++11 mode, and on Visual C++ 2013.
As written, ret_hlp only handles function object types that declare their operator() similarly to lambda closure types, but it can be easily extended to pretty much anything else, including plain function types.
I tried to change the original code as little as possible; I think there's one important bit that needs to be mentioned regarding that code: if compose is given lvalue arguments (as in this example), functionTuple inside compose_impl will store references to those arguments. This means the original functors need to be available for as long as the composite functor is used, otherwise you'll have dangling references.
EDIT: Here's more info on the last note, as requested in the comment:
That behaviour is due to the way forwarding references work - the Fs&& ... function parameters of compose. If you have a function parameter of the form F&& for which template argument deduction is being done (as it is here), and an argument of type A is given for that parameter, then:
if the argument expression is an rvalue, F is deduced as A, and, when substituted back into the function parameter, it gives A&& (for example, this would happen if you passed a lambda expression directly as the argument to compose);
if the argument expression is an lvalue, F is deduced as A&, and, when substituted back into the function parameter, it gives A& &&, which yields A& according to the reference collapsing rules (this is what happens in the current example, as f1 and the others are lvalues).
So, in the current example, compose_impl will be instantiated using the deduced template arguments as something like (using invented names for lambda closure types)
compose_impl<lambda_1_type&, lambda_2_type&, lambda_3_type&>
which in turn will make functionTuple have the type
std::tuple<lambda_1_type&, lambda_2_type&, lambda_3_type&>
If you'd pass the lambda expressions directly as arguments to compose, then, according to the above, functionTuple will have the type
std::tuple<lambda_1_type, lambda_2_type, lambda_3_type>
So, only in the latter case will the tuple store copies of the function objects, making the composed function object type self-contained.
Now, it's not a question of whether this is good or bad; it's rather a question of what you want.
If you want the composed object to always be self-contained (store copies of the functors), then you need to get rid of those references. One way to do it here is to use std::decay, as it does more than remove references - it also handles function-to-pointer conversions, which comes in handy if you want to extend compose_impl to be able to also handle plain functions.
The easiest way is to change the declaration of functionTuple, as it's the only place where you care about references in the current implementation:
std::tuple<typename std::decay<Fs>::type ...> functionTuple;
The result is that the function objects will always be copied or moved inside the tuple, so the resulting composed function object can be used even after the original components have been destructed.
Wow, this got long; maybe you shouldn't have said 'elaborate' :-).
EDIT 2 for the second comment from the OP: Yes, the code as it is, without the std::decay (but extended to properly determine ret_type for plain function arguments, as you said) will handle plain functions, but be careful:
int f(int) { return 7; }
int main()
{
auto c1 = compose(&f, &f); //Stores pointers to function f.
auto c2 = compose(f, f); //Stores references to function f.
auto pf = f; //pf has type int(*)(int), but is an lvalue, as opposed to &f, which is an rvalue.
auto c3 = compose(pf, pf); //Stores references to pointer pf.
std::cout << std::is_same<decltype(c1.functionTuple), std::tuple<int(*)(int), int(*)(int)>>::value << '\n';
std::cout << std::is_same<decltype(c2.functionTuple), std::tuple<int(&)(int), int(&)(int)>>::value << '\n';
std::cout << std::is_same<decltype(c3.functionTuple), std::tuple<int(*&)(int), int(*&)(int)>>::value << '\n';
}
The behaviour of c3 is probably not what you want or what one would expect. Not to mention all these variants will likely confuse your code for determining ret_type.
With the std::decay in place, all three variants store pointers to function f.
EDIT: I use curry below, but have been informed this is instead partial application.
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... ); };
}
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... ); };
}
The tests:
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));
}
Yuck! The line initializing g2 is so large that i might as well have curried it manually.
auto g2 = [](int y){ return 2*y; };
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: No boost, please, but i'll settle if nothing else.
EDIT: 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.
Your curry function is just a scaled down inefficient subcase of std::bind (std::bind1st and bind2nd should not be used anymore now that we have std::result_of)
Your two lines read in fact
auto f5 = std::bind(f, 5, _1);
auto g2 = std::bind(std::multiplies<int>(), 2, _1);
after having used namespace std::placeholders. This carefully avoids the boxing into std::function and allows the compiler to inline more easily the result at the call site.
For functions of two arguments, hacking something like
auto bind1st(F&& f, T&& t)
-> decltype(std::bind(std::forward<F>(f), std::forward<T>(t), _1))
{
return std::bind(std::forward<F>(f), std::forward<T>(t), _1)
}
may work, but it is difficult to generalize to the variadic case (for which you'd end up rewriting a lot of the logic in std::bind).
Also currying is not partial application. Currying has "signature"
((a, b) -> c) -> (a -> b -> c)
ie. it is the action to transform a function taking two arguments into a function returning a function. It has an inverse uncurry performing the reverse operation (for mathematicians: curry and uncurry are isomorphisms, and define an adjunction). This inverse is very cumbersome to write in C++ (hint: use std::result_of).
This is a way to have currying in C++ and may or may not be relevant after the recent edits to the OP.
Due to overloading it is very problematic to inspect a functor and detect its arity. What is possible however is that given a functor f and an argument a, we can check if f(a) is a valid expression. If it isn't, we can store a and given a following argument b we can check if f(a, b) is a valid expression, and so on. To wit:
#include <utility>
#include <tuple>
/* Two SFINAE utilities */
template<typename>
struct void_ { using type = void; };
template<typename T>
using Void = typename void_<T>::type;
// std::result_of doesn't play well with SFINAE so we deliberately avoid it
// and roll our own
// For the sake of simplicity this result_of does not compute the same type
// as std::result_of (e.g. pointer to members)
template<typename Sig, typename Sfinae = void>
struct result_of {};
template<typename Functor, typename... Args>
struct result_of<
Functor(Args...)
, Void<decltype( std::declval<Functor>()(std::declval<Args>()...) )>
> {
using type = decltype( std::declval<Functor>()(std::declval<Args>()...) );
};
template<typename Functor, typename... Args>
using ResultOf = typename result_of<Sig>::type;
template<typename Functor, typename... Args>
class curry_type {
using tuple_type = std::tuple<Args...>;
public:
curry_type(Functor functor, tuple_type args)
: functor(std::forward<Functor>(functor))
, args(std::move(args))
{}
// Same policy as the wrappers from std::bind & others:
// the functor inherits the cv-qualifiers from the wrapper
// you might want to improve on that and inherit ref-qualifiers, too
template<typename Arg>
ResultOf<Functor&(Args..., Arg)>
operator()(Arg&& arg)
{
return invoke(functor, std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))));
}
// Implementation omitted for brevity -- same as above in any case
template<typename Arg>
ResultOf<Functor const&(Args..., Arg)>
operator()(Arg&& arg) const;
// Additional cv-qualified overloads omitted for brevity
// Fallback: keep calm and curry on
// the last ellipsis (...) means that this is a C-style vararg function
// this is a trick to make this overload (and others like it) least
// preferred when it comes to overload resolution
// the Rest pack is here to make for better diagnostics if a user erroenously
// attempts e.g. curry(f)(2, 3) instead of perhaps curry(f)(2)(3)
// note that it is possible to provide the same functionality without this hack
// (which I have no idea is actually permitted, all things considered)
// but requires further facilities (e.g. an is_callable trait)
template<typename Arg, typename... Rest>
curry_type<Functor, Args..., Arg>
operator()(Arg&& arg, Rest const&..., ...)
{
static_assert( sizeof...(Rest) == 0
, "Wrong usage: only pass up to one argument to a curried functor" );
return { std::forward<Functor>(functor), std::tuple_cat(std::move(args), std::forward_as_tuple(std::forward<Arg>(arg))) };
}
// Again, additional overloads omitted
// This is actually not part of the currying functionality
// but is here so that curry(f)() is equivalent of f() iff
// f has a nullary overload
template<typename F = Functor>
ResultOf<F&(Args...)>
operator()()
{
// This check if for sanity -- if I got it right no user can trigger it
// It *is* possible to emit a nice warning if a user attempts
// e.g. curry(f)(4)() but requires further overloads and SFINAE --
// left as an exercise to the reader
static_assert( sizeof...(Args) == 0, "How did you do that?" );
return invoke(functor, std::move(args));
}
// Additional cv-qualified overloads for the nullary case omitted for brevity
private:
Functor functor;
mutable tuple_type args;
template<typename F, typename Tuple, int... Indices>
ResultOf<F(typename std::tuple_element<Indices, Tuple>::type...)>
static invoke(F&& f, Tuple&& tuple, indices<Indices...>)
{
using std::get;
return std::forward<F>(f)(get<Indices>(std::forward<Tuple>(tuple))...);
}
template<typename F, typename Tuple>
static auto invoke(F&& f, Tuple&& tuple)
-> decltype( invoke(std::declval<F>(), std::declval<Tuple>(), indices_for<Tuple>()) )
{
return invoke(std::forward<F>(f), std::forward<Tuple>(tuple), indices_for<Tuple>());
}
};
template<typename Functor>
curry_type<Functor> curry(Functor&& functor)
{ return { std::forward<Functor>(functor), {} }; }
The above code compiles using a snapshot of GCC 4.8 (barring copy-and-paste errors), provided that there is an indices type and an indices_for utility. This question and its answer demonstrates the need and implementation of such things, where seq plays the role of indices and gens can be used to implement a (more convenient) indices_for.
Great care is taken in the above when it comes to value category and lifetime of (possible) temporaries. curry (and its accompanying type, which is an implementation detail) is designed to be as lightweight as possible while still making it very, very safe to use. In particular, usage such as:
foo a;
bar b;
auto f = [](foo a, bar b, baz c, int) { return quux(a, b, c); };
auto curried = curry(f);
auto pass = curried(a);
auto some = pass(b);
auto parameters = some(baz {});
auto result = parameters(0);
does not copy f, a or b; nor does it result in dangling references to temporaries. This all still holds true even if auto is substituted with auto&& (assuming quux is sane, but that's beyond the control of curry). It's still possible to come up with different policies in that regard (e.g. systematically decaying).
Note that parameters (but not the functor) are passed with the same value category in the final call as when they're passed to the curried wrapper. Hence in
auto functor = curry([](foo f, int) {});
auto curried = functor(foo {});
auto r0 = curried(0);
auto r1 = curried(1);
this means that a moved-from foo is passed to the underlying functor when computing r1.
With some C++14 features, partial application that works on lambda's can be implemented in a pretty concise way.
template<typename _function, typename _val>
auto partial( _function foo, _val v )
{
return
[foo, v](auto... rest)
{
return foo(v, rest...);
};
}
template< typename _function, typename _val1, typename... _valrest >
auto partial( _function foo, _val1 val, _valrest... valr )
{
return
[foo,val,valr...](auto... frest)
{
return partial(partial(foo, val), valr...)(frest...);
};
}
// partial application on lambda
int p1 = partial([](int i, int j){ return i-j; }, 6)(2);
int p2 = partial([](int i, int j){ return i-j; }, 6, 2)();
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)() );
}