Using SFINAE with generic lambdas - c++

Can generic lambdas take advantage of the "Substitution Failure Is Not An Error" rule ? Example
auto gL =
[](auto&& func, auto&& param1, auto&&... params)
-> enable_if_t< is_integral<
std::decay_t<decltype(param1)>
>::value>
{
// ...
};
auto gL =
[](auto&& func, auto&& param1, auto&&... params)
-> enable_if_t< !is_integral<
std::decay_t<decltype(param1)>
>::value>
{
// ...
};
Are there any workarounds or plans to include this in the language ? Also since generic lambdas are templated function objects under the hood isn't it a bit odd that this can't be done ?

Lambdas are function objects under the hood. Generic lambdas are function objects with template operator()s.
template<class...Fs>
struct funcs_t{};
template<class F0, class...Fs>
struct funcs_t<F0, Fs...>: F0, funcs_t<Fs...> {
funcs_t(F0 f0, Fs... fs):
F0(std::move(f0)),
funcs_t<Fs...>(std::move(fs)...)
{}
using F0::operator();
using funcs_t<Fs...>::operator();
};
template<class F>
struct funcs_t<F>:F {
funcs_t(F f):F(std::move(f)){};
using F::operator();
};
template<class...Fs>
funcs_t< std::decay_t<Fs>... > funcs(Fs&&...fs) {
return {std::forward<Fs>(fs)...};
}
auto f_all = funcs( f1, f2 ) generates an object that is an overload of both f1 and f2.
auto g_integral =
[](auto&& func, auto&& param1, auto&&... params)
-> std::enable_if_t< std::is_integral<
std::decay_t<decltype(param1)>
>{}>
{
// ...
};
auto g_not_integral =
[](auto&& func, auto&& param1, auto&&... params)
-> std::enable_if_t< !std::is_integral<
std::decay_t<decltype(param1)>
>{}>
{
// ...
};
auto gL = funcs( g_not_integral, g_integral );
and calling gL will do SFINAE friendly overload resolution on the two lambdas.
The above does some spurious moves, which could be avoided, in the linear inheritance of funcs_t. In an industrial quality library, I might make the inheritance binary rather than linear (to limit instantiation depth of templates, and the depth of the inheritance tree).
As an aside, there are 4 reasons I know of to SFINAE enable lambdas.
First, with new std::function, you can overload a function on multiple different callback signatures.
Second, the above trick.
Third, currying a function object where it evaluates when it has the right number and type of args.
Forth, automatic tuple unpacking and similar. If I'm using continuation passing style, I can ask the passed in continuation if it will accept the tuple unpacked, or the future unbundled, etc.

A generic lambda can only have one body, so SFINAE wouldn't be of much use here.
One solution would be to package the call into a class which can store the result and is specialized on a void return type, encapsulating the void special handling away from your lambda. With a very little overhead, you can do this using the thread library facilities:
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
std::packaged_task<Ret()> task{[&]{
return std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...); }};
auto fut = task.get_future();
task();
// stop timer and print elapsed time
return fut.get();
};
If you want to avoid the overhead of packaged_task and future, it's easy to write your own version:
template<class T>
struct Result
{
template<class F, class... A> Result(F&& f, A&&... args)
: t{std::forward<F>(f)(std::forward<A>(args)...)} {}
T t;
T&& get() { return std::move(t); }
};
template<>
struct Result<void>
{
template<class F, class... A> Result(F&& f, A&&... args)
{ std::forward<F>(f)(std::forward<A>(args)...); }
void get() {}
};
auto gL =
[](auto&& func, auto&&... params)
{
// start a timer
using Ret = decltype(std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...));
Result<Ret> k{std::forward<decltype(func)>(func),
std::forward<decltype(params)>(params)...};
// stop timer and print elapsed time
return k.get();
};

The use of SFINAE is to remove an overload or a specialization from the candidate set when resolving a given function or template. In your case, we have a lambda - that is a functor with a single operator(). There is no overload, so there is no reason to use SFINAE1. The fact that the lambda is generic, which makes its operator() a function template, doesn't change that fact.
However, you don't actually need to differentiate between different return types. If func returns void for the given arguments, you can still return it. You just can't assign it to a temporary. But you don't have to do that either:
auto time_func = [](auto&& func, auto&&... params) {
RaiiTimer t;
return std::forward<decltype(func)>(func)(
std::forward<decltype(params)>(params)...);
};
Just write an RaiiTimer whose constructor starts a timer and whose destructor stops it and prints the result. This will work regardless of func's return type.
If you need something more complicated than that, then this is one of those cases where you should prefer a functor over a lambda.
1Actually, as Yakk points out, SFINAE could still be quite handy to check if your function is callable period, which isn't the problem you're trying to solve - so in this case, still not very helpful.

Related

Mimic std::bind_front in c++17 for calling member functions

Is it somehow possible to easily mimic std::bind_front in C++17 ? (just for member function wrapping is fine)
I took a look at implementation in c++20 aiming to copy but it seems its very much implementation specific indeed.
I'm thinking a lambda wrapper or template function/object might work?
(Performance is not an issue here)
This can be a starting point
template<typename F, typename ...FrontArgs>
struct bindfronthelper
{
bindfronthelper(F f, FrontArgs&&...args)
: mF{std::move(f)}
, mFrontArg{std::forward<FrontArgs>(args)...}
{}
template<typename ...BackArgs>
auto operator()(BackArgs&&...args) const
{
return std::apply(mF, std::tuple_cat(mFrontArg, std::forward_as_tuple(args...)));
}
F mF;
std::tuple<std::decay_t<FrontArgs>...> mFrontArg;
};
template<typename F, typename ...FrontArgs>
auto mybindfront(F f, FrontArgs&&...args)
{
return bindfronthelper<F, FrontArgs...>{std::move(f), std::forward<FrontArgs>(args)...};
}
https://godbolt.org/z/Tz9fen
Written quickly and not tested well, so there might be some pitfalls in corner cases. At least it shows how this can be achieved.
Ok I made this over complicated, here is simpler version:
template<typename T, typename ...Args>
auto tuple_append(T&& t, Args&&...args)
{
return std::tuple_cat(
std::forward<T>(t),
std::forward_as_tuple(args...)
);
}
template<typename F, typename ...FrontArgs>
decltype(auto) mybindfront(F&& f, FrontArgs&&...frontArgs)
{
return [f=std::forward<F>(f),
frontArgs = std::make_tuple(std::forward<FrontArgs>(frontArgs)...)]
(auto&&...backArgs)
{
return std::apply(
f,
tuple_append(
frontArgs,
std::forward<decltype(backArgs)>(backArgs)...));
};
}
https://godbolt.org/z/cqPjTY
still passes all test I've provided. I'm keeping old version since with a bit of work it can be tweaked to work with older standard of c++.
One really simpel way I found is with lambda's (in this case capturing this - but you can change that easily to be generally adoptable):
auto bind_m = [this](auto mem_f) {
auto wrapper = [=] (auto&&... args) {return std::mem_fn(mem_f)(this, std::forward<decltype(args)>(args)...);};
return wrapper;
};
The lambda creates another lambda and returns it.
template<typename F, typename... FRONT_ARGS>
auto bind_front(F&& f, FRONT_ARGS&&... front_args)
{
// front_args are copied because multiple invocations of this closure are possible
return [captured_f = std::forward<F>(f), front_args...](auto&&... back_args) {
return std::invoke(captured_f, front_args...,
std::forward<decltype(back_args)>(back_args)...);
};
}

Alternative for std::bind in modern C++

So I'm trying to create a class which has a container for functors of a different type.
This is a simplified version of it.
template<class T>
class Container
{
public:
template<typename F, typename ... ARGS>
void addTask(F && func, ARGS && ... args);
private:
std::deque<std::function<T()>> container;
//.....
};
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args);
{
container.emplace_back(std::bind(f,args...));
//.....
}
There are still few problems that I cannot solve yet.
Is there a way to remove std::bind and store a different object or a pointer?
Could this be more generic? Can I somehow store functions, which return different objects, in a single container(int,void...)?
Can some of the logic for creating the tasks be executed in compile time?Something like consexpr bind.
From a comment by the OP.
There are. This is simplified. I'm using futures and a special container in the real code. It is meant to be used in a multithreading environment
This is called burying the lede.
If you are storing callables to be invoked in other threads, in the other thread you want signature void(). In this thread you want a std::future to be populated.
As for binding arguments, while a number of std functions do this for you, I find it is best to ask for callables with pre-bound arguments. They can do it outside, using std::bind or lambdas or whatever other means they choose.
So this then comes
template<class Func,
class R = std::decay_t<std::result_of_t<Func const&()>>
>
std::future< R >
addTask( Func&& func ) {
auto task = std::packaged_task<R()>(std::forward<Func>(func));
auto ret = task.get_future();
container.push_back( std::packaged_task<void()>( std::move(task) ) );
return ret;
}
std::deque< std::packaged_task<void()> > container;
throw in some mutexes and shake and bake.
Here I use std::packaged_task<void()> as a pre-written move-only type-erased container for anything with that signature. We don't use the future it can produce, which is a waste, but it is shorter than writing your own move-only invoke-once owning function object.
I personally just wrote myself a light weight move-only std::function<void()> esque class instead of using std::packaged_task<void()>, but it was probably unwise.
The future returned from addTask gets fullfilled when the packaged_task<R()> is invoked, which is invoked when the packaged_task<void()> is invoked (possibly in another thread).
Outside of the structure, callers can give you any zero-argument callable object.
99 times out of 100, a simple [some_arg]{ some_code; } or even []{ some_code; } works. In complex cases they can mess around with std::bind or C++14 improvements with more complex lambdas.
Putting the storing of the arguments into addTask mixes the responsibility of the thread-task-queue with messing with arguments.
In fact, I'd write a thread-safe queue separately from my thread-pool, and have the thread-pool use it:
template<class T>
struct thread_safe_queue;
struct thread_pool {
thread_safe_queue< std::packaged_task<void()> > queue;
// etc
};
In C++17, a replacement for your bind looks like:
[
func = std::forward<Func>(func),
args = std::make_tuple( std::forward<Args>(args)... )
]() mutable {
std::apply( func, std::move(args) );
}
In C++14 you can write notstd::apply pretty easy. Move-into-lambda requires C++14, so if you need to efficiently move arguments you need std bind or a manual function object in C++11.
I will argue that placing the argument binding strongly in the domain of the code using the thread pool is best.
That also permits the thread pool to do things like pass the tasks optional extra arguments, like "cancellation tokens" or the like.
std::bind came from boost::bind, which was necessary before we had lambdas.
Unfortunately std::bind made it into the standard at the same time as lambdas, so it was immediately almost irrelevant.
In c++14 and beyond you can capture the function and args in a variadic lambda:
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args)
{
container.emplace_back( [func = std::forward<F>(func),
args...]
() mutable // make mutable if you want to move the args in to func
{
return func(std::move(args)...);
});
//.....
}
You don't quite get perfect forwarding this way. There is a copy implicit in the capture of args...
This solved in c++17
template<class T>
template<typename F, typename ... ARGS>
T Container<T>::addTask(F && func, ARGS && ... args)
{
container.emplace_back( [func = std::forward<F>(func),
args = std::make_tuple(std::forward<ARGS>(args)...) ]
() mutable // make mutable if you want to move the args in to func
{
return std::apply(func, std::move(args));
});
//.....
}

Function wrapper that works for all kinds of functors without casting

I'd like to create a function that takes a weak pointer and any kind of functor (lambda, std::function, whatever) and returns a new functor that only executes the original functor when the pointer was not removed in the meantime (so let's assume there is a WeakPointer type with such semantics). This should all work for any functor without having to specify explicitly the functor signature through template parameters or a cast.
EDIT:
Some commenters have pointed out that std::function - which I used in my approach - might not be needed at all and neither might the lambda (though in my original question I also forgot to mention that I need to capture the weak pointer parameter), so any alternative solution that solves the general problem is of course is also highly appreciated, maybe I didn't think enough outside the box and was to focused on using a lambda + std::function. In any case, here goes what I tried so far:
template<typename... ArgumentTypes>
inline std::function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const std::function<void(ArgumentTypes...)>&& fun)
{
return [=] (ArgumentTypes... args)
{
if(pWeakPointer)
{
fun(args...);
}
};
}
This works well without having to explicitly specify the argument types if I pass an std::function, but fails if I pass a lambda expression. I guess this because the std::function constructor ambiguity as asked in this question. In any case, I tried the following helper to be able to capture any kind of function:
template<typename F, typename... ArgumentTypes>
inline function<void(ArgumentTypes...)> wrap(WeakPointer pWeakPointer, const F&& fun)
{
return wrap(pWeakPointer, std::function<void(ArgumentTypes...)>(fun));
}
This now works for lambdas that don't have parameters but fails for other ones, since it always instantiates ArgumentTypes... with an empty set.
I can think of two solution to the problem, but didn't manage to implement either of them:
Make sure that the correct std::function (or another Functor helper type) is created for a lambda, i.e. that a lambda with signature R(T1) results in a std::function(R(T1)) so that the ArgumentTypes... will be correctly deduced
Do not put the ArgumentTypes... as a template parameter instead have some other way (boost?) to get the argument pack from the lambda/functor, so I could do something like this:
-
template<typename F>
inline auto wrap(WeakPointer pWeakPointer, const F&& fun) -> std::function<void(arg_pack_from_functor(fun))>
{
return wrap(pWeakPointer, std::function<void(arg_pack_from_functor(fun))(fun));
}
You don't have to use a lambda.
#include <iostream>
#include <type_traits>
template <typename F>
struct Wrapper {
F f;
template <typename... T>
auto operator()(T&&... args) -> typename std::result_of<F(T...)>::type {
std::cout << "calling f with " << sizeof...(args) << " arguments.\n";
return f(std::forward<T>(args)...);
}
};
template <typename F>
Wrapper<F> wrap(F&& f) {
return {std::forward<F>(f)};
}
int main() {
auto f = wrap([](int x, int y) { return x + y; });
std::cout << f(2, 3) << std::endl;
return 0;
}
Assuming the weak pointer takes the place of the first argument, here's how I would do it with a generic lambda (with move captures) and if C++ would allow me to return such a lambda:
template<typename Functor, typename Arg, typename... Args>
auto wrap(Functor&& functor, Arg&& arg)
{
return [functor = std::forward<Functor>(functor)
, arg = std::forward<Arg>(arg)]<typename... Rest>(Rest&&... rest)
{
if(auto e = arg.lock()) {
return functor(*e, std::forward<Rest>(rest)...);
} else {
// Let's handwave this for the time being
}
};
}
It is possible to translate this hypothetical code into actual C++11 code if we manually 'unroll' the generic lambda into a polymorphic functor:
template<typename F, typename Pointer>
struct wrap_type {
F f;
Pointer pointer;
template<typename... Rest>
auto operator()(Rest&&... rest)
-> decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )
{
if(auto p = lock()) {
return f(*p, std::forward<Rest>(rest)...);
} else {
// Handle
}
}
};
template<typename F, typename Pointer>
wrap_type<typename std::decay<F>::type, typename std::decay<Pointer>::type>
wrap(F&& f, Pointer&& pointer)
{ return { std::forward<F>(f), std::forward<Pointer>(pointer) }; }
There are two straightforward options for handling the case where the pointer has expired: either propagate an exception, or return an out-of-band value. In the latter case the return type would become e.g. optional<decltype( f(*pointer.lock(), std::forward<Rest>(rest)...) )> and // Handle would become return {};.
Example code to see everything in action.
[ Exercise for the ambitious: improve the code so that it's possible to use auto g = wrap(f, w, 4); auto r = g();. Then, if it's not already the case, improve it further so that auto g = wrap(f, w1, 4, w5); is also possible and 'does the right thing'. ]

std::bind with pointer to a function object

Given a pointer to a function object:
std::shared_ptr<std::function<double(double)>> f;
is there a built-in construct in C++11 that allows be to use this pointer in a std::bind statement? For example:
std::function<double()> g = std::bind(built_in(f), 0.0);
What I am doing is to use variadic template as:
template<typename Ret, typename... Args>
std::function<Ret(Args...)> get_fn(const std::shared_ptr<std::function<Ret(Args...)>>& f)
{
return [=](Args... args) -> Ret { return (*f)(args...); };
}
This allows me to write:
std::function<double()> g = std::bind(get_fn(f), 0.0);
Thanks in advance.
Edit: I should have been clearer. I need to use the instance of the function object inside the shared pointer for optimization purposes.
If we had a Standard function object for the dereference operator (much like std::plus<T> is for adding T with T) then we could involve a nested bind expression, but that is not the case -- plus we'd need a call operator because the usual substitutions that take place during the evaluation of nested bind expressions don't apply to the first argument! Your solution introduces an additional std::function, so I'm proposing some alternatives that don't.
Write your own call and dereference operators:
struct call {
template<typename Callable, typename... Args>
auto operator()(Callable&& callable, Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Callable>()(std::declval<Args>()...) )
{ return std::forward<Callable>(callable)(std::forward<Args>(args)...); }
};
struct dereference {
template<typename T>
auto operator()(T&& t) const
-> decltype( *std::declval<T>() )
{ return *std::forward<T>(t); }
};
template<typename IndirectCallable, typename... Args>
auto indirect_bind(IndirectCallable&& f, Args&&... args)
-> decltype( std::bind(call {}
, std::bind(dereference {}, std::declval<IndirectCallable>())
, std::declval<Args>()... ) )
{ return std::bind(call {}
, std::bind(dereference {}, std::forward<IndirectCallable>(f))
, std::forward<Args>()... ); }
You can then do auto g = indirect_bind(f, 0.0);. Here's a proof-of-concept that also shows how placeholders are appropriately dealt with.
I mention the above solution because functors like call and dereference are useful bricks -- I personally have them among my tools. My preferred solution however would be to write a polymorphic functor that does the indirection and call in one go:
template<typename Indirect>
struct indirect_callable_type {
// Encapsulation left as an exercise
Indirect f;
template<typename... Args>
auto operator()(Args&&... args)
// don't use std::result_of
-> decltype( std::declval<Indirect&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
template<typename... Args>
auto operator()(Args&&... args) const
// don't use std::result_of
-> decltype( std::declval<Indirect const&>()(std::declval<Args>()...) )
{ return f(std::forward<Args>(args)...); }
// Lvalue and rvalue *this version also left as an exercise
};
template<typename T>
indirect_callable_type<typename std::decay<T>::type>
make_indirect_callable(T&& t)
{ return { std::forward<T>(t) }; }
which you can, in fact, use as auto g = std::bind(make_indirect_callable(f), 0.0);.
I should mention that unlike your solution, those requires writing some types out-of-line. This is an unfortunate situation due to the inherent limitations of lambda expressions. Should you wish to stick with what you currently have, I have a minor recommendation that inside the lambda you std::forward<Args>(args)... the parameters. This might prove useful if you ever deal with move-only types.
There's a nice little hack you can use here, which is that INVOKE on a pointer to member function automatically indirects its object argument when passed a pointer or (even) a smart pointer (20.8.2p1 second bullet, definition of INVOKE):
#include <functional>
#include <memory>
#include <iostream>
int main() {
std::shared_ptr<std::function<double(double)>> f
= std::make_shared<std::function<double(double)>>(
[](double d) { return d + 10.0; });
std::function<double()> g = std::bind(
&std::function<double(double)>::operator(), f, 0.0);
std::cout << g() << std::endl;
}
If you don't want to mention explicitly the type of f:
std::function<double()> g = std::bind(
&std::remove_reference<decltype(*f)>::type::operator(), f, 0.0);

Partial application with a C++ lambda?

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)() );
}