Related
env->CallObjectMethod(hashMapInstance, put, _, _)
I want to call this function with all the possible permutations of std::string, int, double on the underscores. For example:
env->CallObjectMethod(hashMapInstance, put, myString, myInt)
env->CallObjectMethod(hashMapInstance, put, myInt, myDouble)
env->CallObjectMethod(hashMapInstance, put, myInt, myInt)
//...
Of course I can do this with nested ifs but I'd be reusing the same code on lots of places. Ideally I'd like a way to receive a std::map<JavaObject, JavaObject> myMap and then for each pair on the map, do the following:
for (auto pair : myMap)
if (pair.first.type == JavaObject::String && pair.second.type == JavaObject::Integer)
env->CallObjectMethod(hashMapInstance, put, pair.first.getString(), pair.second.getInt())
//OR
if (pair.first.type == JavaObject::Integer && pair.second.type == JavaObject::Integer)
env->CallObjectMethod(hashMapInstance, put, pair.first.getInt(), pair.second.getInt()) //
//OR
if (pair.first.type == JavaObject::Double && pair.second.type == JavaObject::String)
env->CallObjectMethod(hashMapInstance, put, pair.first.getDouble(), pair.second.getString())
//...
as you can see, I need a way to efficiently be able to call each permutation env->CallObjectMethod(hashMapInstance, put, _, _) for every possible permutation of JavaObject, JavaObject received (JavaObject is just a class that can hold string, int, double and possibly more in the future)
The first thing I thought was to create a templated function:
template<typename T, typename V>
void myCallobjectMethod(env, jobject instance, jmethodID method, T obj1, V obj2)
But I still have to read JavaObject.type for the first item and then inside this if, do another if for the second part, just to call my templated function, so I'm still with the same problem.
I thought of another way, in pseudocode:
using namespace std::placeholders;
for (auto pair : myMap)
auto bind1 = std::bind(env->CallObjectMethod, hashMapInstance, put, _3, _4); //binds the hashMapInstance and put
auto bind2 = std::bind(bind1, pair.first, _2); //binds the first object
auto bind3 = std::bind(bin2, pair.second); //binds the second object
bind3(); //now I can call bind3 to execute the call
but it's not that simple, I don't even know what's happening to the types of things here.
JavaObject is a sum type, so it should have a visit function:
template<class F> auto visit(F&& f, JavaObject const& o) {
switch (o.type) {
case JavaObject::String : return f(o.getString());
case JavaObject::Integer : return f(o.getInt());
case JavaObject::Double : return f(o.getDouble());
}
}
Any unary visit function can be composed with itself to operate on 2 arguments:
template<class F> auto visit(F&& f, JavaObject const& o1, JavaObject const& o2) {
return visit([&](auto const& x1) {
return visit([&](auto const& x2) {
return f(x1, x2); }, o2); }, o1);
}
Now you can write:
visit([&](auto const& x1, auto const& x2) {
env->CallObjectMethod(hashMapInstance, put, x1, x2);
}, pair.first, pair.second);
Extending visit to arbitrary arity is left as an exercise for the reader (Hint: use recursion).
In addition to ecatmur's answer, I am going to give some hint on how to do the permutation:
#include <functional>
#include <iostream>
#include <tuple>
void test(int a, int b, int c, int d, int e, int f, int g) {
std::cout << a << " " << b << " " << c << " " << d << " " << e << " " << f << " " << g << std::endl;
}
template <typename ReturnT, typename T, typename U, typename ... TRestArgs>
auto easy_bind(std::function<ReturnT(T, TRestArgs...)> func, U&& arg) -> std::function<ReturnT(TRestArgs...)> {
if constexpr (std::is_same_v<void, ReturnT>) {
return [=](TRestArgs... args) { func(arg, args...); };
}
else {
return [=](TRestArgs... args) { return func(arg, args...); };
}
}
template <typename CallableT, typename ... TArgs, std::size_t ... SeqLeft, std::size_t ... SeqRight>
void permute_call_impl(CallableT func, std::tuple<TArgs...> args, std::index_sequence<SeqLeft...>, std::index_sequence<SeqRight...>);
template <typename CallableT, typename ... TArgs, std::size_t ... Seq>
void permute_call_splitter(CallableT func, std::tuple<TArgs...> args, std::index_sequence<Seq...>);
template <typename CallableT, typename ... TArgs, std::size_t ... SeqLeft, std::size_t ... SeqRight>
void permute_call_impl(CallableT func, std::tuple<TArgs...> args, std::index_sequence<SeqLeft...>, std::index_sequence<SeqRight...>) {
if constexpr (sizeof...(SeqLeft) + sizeof...(SeqRight) == 0u) {
func();
}
else {
permute_call_splitter(func,
std::make_tuple(std::get<SeqLeft>(args)..., std::get<SeqRight + sizeof...(SeqLeft) + 1>(args)...),
std::make_index_sequence<sizeof...(SeqLeft) + sizeof...(SeqRight)>{}
);
}
}
template <typename CallableT, typename ... TArgs, std::size_t ... Seq>
void permute_call_splitter(CallableT func, std::tuple<TArgs...> args, std::index_sequence<Seq...>) {
constexpr auto size = sizeof...(Seq);
(permute_call_impl(easy_bind(func, std::get<Seq>(args)),
args,
std::make_index_sequence<Seq>{},
std::make_index_sequence<size - 1u - Seq>{}
), ...);
}
template <typename CallableT, typename ... TArgs>
void permute_call(CallableT func, TArgs... args) {
permute_call_splitter(func, std::make_tuple(args...), std::make_index_sequence<sizeof...(TArgs)>{});
}
int main() {
std::function func = test;
permute_call(func, 1, 2, 3, 4, 5, 6, 7);
return 0;
}
So basically you have a std::index_sequence, you iterate on every index, remove the element, merge the rest two parts, and pass it to the next level of recursion.
I did not take care of reference forwarding in this example, for now. But it would gives you a rough idea about how things should work.
Live Example
Here's what I want to do; posting the whole code because it's not too long and also to demonstrate the specific task I'm trying to solve. Basically, I need a way to iterate values from parameter pack by index (the index part is important, even though it's not required in this example).
#include <iostream>
#include <tuple>
#include <type_traits>
template <int First, int Last, typename Functor>
constexpr void static_for(Functor&& f)
{
if constexpr (First < Last)
{
f(std::integral_constant<int, First>{});
static_for<First + 1, Last, Functor>(std::forward<Functor>(f));
}
}
template <size_t index, typename... Args>
auto value_by_index(Args&&... args) noexcept {
return std::get<index>(std::forward_as_tuple(std::forward<Args>(args)...));
}
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](int i) {
auto v = value_by_index<static_cast<size_t>(i), ValueTypes...>(values...);
std::cout << v << std::endl;
});
}
int main()
{
traverse(0.0f, 1, 3.33, "str");
return 0;
}
The compiler error, of course, is:
<source>:24:71: error: 'i' is not a constant expression
If lambdas could have explicit template arguments, i would be such an argument and it would be obvious to the compiler that it's known at compile time. But that's not how lambdas work.
If you want to treat it as an X-Y problem, I suppose I don't specifically need to call a lambda inside my static_for, but I do need to call some piece of code that can access parameter pack(s) of traverse by index, and if traverse was a member function, I need to have access to its this.
Try it online: https://godbolt.org/z/eW4rnm
Use a generic lambda and a constexpr conversion operator c++17:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&](auto I)
// ~~~^
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
DEMO
Use a template parameter list for the lambda expression c++20:
template <typename... ValueTypes>
void traverse(ValueTypes... values)
{
static_for<0, sizeof...(ValueTypes)>([&]<int I>(std::integral_constant<int, I>)
// ~~~~^ ~^~
{
auto v = value_by_index<I>(values...);
// ~^~
std::cout << v << std::endl;
});
}
DEMO 2
It's too late to play?
Basically, I need a way to iterate values from parameter pack by index (the index part is important, even though it's not required in this example).
Sorry but... what about the good old use of std::make_index_sequence and std::index_sequence ?
Maintaining your value_by_index(), I propose the following C++14 solution based on traverse() with traverse_helper()
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
Observe that I've passed also the callable as parameter.
If you can use C++17 (as you tagged), traverse_helper() simply become
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{ (f(value_by_index<Is>(vs...)), ...); }
You can call traverse() as follows
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
The following is a full C++14 compiling example
#include <iostream>
#include <tuple>
#include <type_traits>
template <std::size_t I, typename ... As>
auto value_by_index (As && ... as) noexcept
{ return std::get<I>(std::forward_as_tuple(std::forward<As>(as)...)); }
template <typename F, std::size_t ... Is, typename ... VTs>
void traverse_helper (F f, std::index_sequence<Is...>, VTs ... vs)
{
using unused = int[];
(void)unused { 0, (f(value_by_index<Is>(vs...)), 0)... };
}
template <typename F, typename ... VTs>
void traverse (F f, VTs ... vs)
{ traverse_helper(f, std::make_index_sequence<sizeof...(VTs)>{}, vs...); }
int main ()
{
traverse([](auto x){ std::cout << x << std::endl; },
0.0f, 1, 3.33, "str");
}
I have a family of classes with methods with the following signature:
double compute(list<T> pars)
This method performs a calculation with the parameters received through pars. For each compute(list) method, I have another compute(x1, x2, ..., xn) which is the method implementing the real calculation. Thus, compute(pars) should do some such as:
double compute(list<T> pars)
{
T x1 = list.pop_back();
T x2 = list.pop_back();
// .. so on until last parameter xn
T xn = list.pop_back();
return compute(x1, x2, .., xn); // here the real implementation is called
}
This pattern repeats many times, the only thing that could change is the size of pars list and of course the implementation of compute(x1, x1, ..).
I would like to find a way for "driying" this repetitive process; concretely, extracting the parameters in pars list and building the call to compute(x1, x2, .., xn). I have been trying without success to do some macro tricks.
My question is if it exists some way based on metaprogramming that allows me to implement compute(list<T> pars) once and simply reuse it n order to perform the call to compute(x1, x2, ..., xn)
EDIT: This is the signature of the other compute(x1, ...)
VtlQuantity compute(const VtlQuantity & x1,
const VtlQuantity & x2,
// any number of pars according the class
const VtlQuantity & xn) const
'VtlQuantityis a class representingdouble`'s, their units and other stuff.
You may do the following:
template <typename Func, typename T, std::size_t ... Is>
decltype(auto) apply(Func&& f, const std::list<T>& pars, std::index_sequence<Is...>)
{
std::vector<T> v(pars.rbegin(), pars.rend());
return std::forward<Func>(f)(v.at(Is)...);
}
template <std::size_t N, typename Func, typename T>
decltype(auto) apply(Func&& f, const std::list<T>& pars)
{
return apply(std::forward<Func>(f), pars, std::make_index_sequence<N>());
}
With usage similar to:
apply<6>(print, l);
Demo
To compute automatically the arity of the function, you may create a traits:
template <typename F> struct arity;
template <typename Ret, typename ...Args> struct arity<Ret(Args...)>
{
static constexpr std::size_t value = sizeof...(Args);
};
and then
template <typename Func, typename T>
decltype(auto) apply(Func&& f, const std::list<T>& pars)
{
constexpr std::size_t N = arity<std::remove_pointer_t<std::decay_t<Func>>>::value;
return apply(std::forward<Func>(f), pars, std::make_index_sequence<N>());
}
Demo
You have to enrich arity to support Functor (as the lambda).
This is a C++11 solution for the more general problem type of applying
a function or functor F, taking N type T parameters and returning type Ret, to the N arguments
at successive positions of some input iterator.
This gains several flexibilities over a solution parameterized by some container-of-T of the arguments:-
You can extract the arguments from an arbitrary N-sized range within a sequence.
The sequence need not be a container-of-T - though it must be a sequence of something convertible to T.
You can extract the arguments either last-to-first (as you do), or first-to-last,
from the standard container types or any that support forward and reverse iterators.
You may even apply F to arguments consumed directly from some input stream, without
intermediate extraction.
And of course you can change your mind about the type of sequence in which
to deliver arguments without having to change the functional-application solution.
Interface
template<typename Func, typename InIter, typename Stop = std::nullptr_t>
typename function_traits<typename std::decay<Func>::type>::return_type
invoke(Func && f, InIter it, Stop stop = Stop());
You can use this like:
auto result = invoke(func,iter);
to apply func to the arguments at N successive positions of the iterator
iter.
That way, you get no range-checking that N arguments are legitimately accessible
to your program at those positions. The range-checking code that you will spot
in the implementation will compile to nothing and if you trespass out of bounds
there will be UB.
If you want range checking you can instead code:
auto result = invoke(func,iter,end);
where end is an iterator of the same type as iter delimiting the end of the
available range in the usual manner. In this case an std::out_of_range will
be thrown if N exceeds the size of the range.
Implementation
#include <type_traits>
#include <functional>
#include <string>
template<typename T>
struct function_traits;
template <typename Ret, typename ArgT, typename... ArgRest>
struct function_traits<Ret(*)(ArgT, ArgRest...)>
{
static constexpr std::size_t n_args = 1 + sizeof...(ArgRest);
using first_arg_type = ArgT;
using return_type = Ret;
};
template <typename Ret, typename ArgT, typename... ArgRest>
struct function_traits<std::function<Ret(ArgT, ArgRest...)>>
{
static constexpr std::size_t n_args = 1 + sizeof...(ArgRest);
using first_arg_type = ArgT;
using return_type = Ret;
};
namespace detail {
template<typename Left, typename Right>
typename std::enable_if<!std::is_same<Left,Right>::value>::type
range_check(Left, Right, std::string const &){}
template<typename Left, typename Right>
typename std::enable_if<std::is_same<Left,Right>::value>::type
range_check(Left start, Right end, std::string const & gripe) {
if (start == end) {
throw std::out_of_range(gripe);
}
}
template<
std::size_t N, typename Func, typename InIter, typename Stop,
typename ...Ts
>
typename std::enable_if<
N == function_traits<typename std::decay<Func>::type>::n_args,
typename function_traits<typename std::decay<Func>::type>::return_type
>::type
invoke(Func && f, InIter, Stop, Ts...args)
{
return f(args...);
}
template<
std::size_t N, typename Func, typename InIter, typename Stop,
typename ...Ts
>
typename std::enable_if<
N != function_traits<typename std::decay<Func>::type>::n_args,
typename function_traits<typename std::decay<Func>::type>::return_type
>::type
invoke(Func && f, InIter it, Stop stop, Ts...args)
{
range_check(it,stop,
"Function takes more arguments than are available "
"in `" + std::string(__PRETTY_FUNCTION__) + '`');
using arg_type = typename
function_traits<typename std::decay<Func>::type>::first_arg_type;
auto arg = static_cast<arg_type>(*it);
return invoke<N + 1>(std::forward<Func>(f),++it,stop,args...,arg);
}
} // namespace detail
template<typename Func, typename InIter, typename Stop = std::nullptr_t>
typename function_traits<typename std::decay<Func>::type>::return_type
invoke(Func && f, InIter it, Stop stop = Stop())
{
return detail::invoke<0>(std::forward<Func>(f),it,stop);
}
The two specializations of function_traits<T> provided will restrict
compilation to functional types T that take at least one argument, which should
suffice for likely applications. Should you need to support
invocation on types taking 0 arguments then you can augment them with:
template <typename Ret>
struct function_traits<Ret(*)()>
{
static constexpr std::size_t n_args = 0;
using return_type = Ret;
};
template <typename Ret>
struct function_traits<std::function<Ret()>>
{
static constexpr std::size_t n_args = 0;
using return_type = Ret;
};
The specialization for free functions function_traits<Ret(*)(ArgT, ArgRest...)>,
is strictly a redundant convenience, since they too could be wrapped in std::function
objects, as you're obliged to do for anything fancier than a free function.
Demo
For a program that exercises the features discussed you can append:
#include <iostream>
#include <list>
#include <vector>
#include <deque>
#include <sstream>
#include <iterator>
struct num
{
double d;
explicit operator double() const {
return d;
}
};
double add4(double d0, double d1, double d2, double d3)
{
std::cout << d0 << '+' << d1 << '+' << d2 << '+' << d3 << "\n=";
return d0 + d1 + d2 + d3;
}
int multiply2(int i0, int i1)
{
std::cout << i0 << '*' << i1 << "\n=";
return i0 * i1;
}
struct S
{
int subtract3(int i0, int i1, int i2) const
{
std::cout << i0 << '-' << i1 << '-' << i2 << "\n=";
return i0 - i1 - i2;
}
int compute(std::list<int> const & li) const {
std::function<int(int,int,int)> bind = [this](int i0, int i1, int i2) {
return this->subtract3(i0,i1,i2);
};
return invoke(bind,li.begin());
}
};
int main()
{
std::vector<double> vd{1.0,2.0,3.0,4.0};
std::vector<double> vdshort{9.0};
std::list<int> li{5,6,7,8};
std::deque<num> dn{num{10.0},num{20.0},num{30.0},num{40.0}};
std::istringstream iss{std::string{"10 9 8"}};
std::istream_iterator<int> it(iss);
std::cout << invoke(add4,vd.rbegin()) << '\n';
std::cout << invoke(multiply2,li.begin()) << '\n';
std::cout << invoke(add4,dn.rbegin()) << '\n';
std::cout << invoke(multiply2,++it) << '\n';
S s;
std::cout << '=' << s.compute(li) << '\n';
try {
std::cout << invoke(add4,vdshort.begin(),vdshort.end()) << '\n';
} catch(std::out_of_range const & gripe) {
std::cout << "Oops :(\n" << gripe.what() << '\n';
}
return 0;
}
The case of:
S s;
std::cout << '=' << s.compute(li) << '\n';
is particularly pertinent to your particular problem, since here we call
S::compute(std::list<int> const & li) to apply another non-static method
of S to arguments delivered in the list li. See in the implementation
of S::compute how the use of a lambda can conveniently bind both the
calling S object and S::compute into an std::function we can
pass to invoke.
Live demo
C++17 solution below. wandbox link
(Greatly simplified thanks to Jarod42)
Assumes the number of arguments N is known at compile-time, but the list can have any size.
This calls pop_back() multiple times as shown in the example, then calls a function.
template <typename T>
struct list
{
T pop_back() { return T{}; }
};
namespace impl
{
template<typename TList, std::size_t... TIs>
auto list_to_tuple(TList& l, std::index_sequence<TIs...>)
{
using my_tuple = decltype(std::make_tuple((TIs, l.pop_back())...));
return my_tuple{((void)TIs, l.pop_back())...};
}
}
template<std::size_t TN, typename TList>
auto list_to_tuple(TList& l)
{
return impl::list_to_tuple(l, std::make_index_sequence<TN>());
}
template <std::size_t TN, typename TList, typename TF>
auto call_with_list(TList& l, TF&& f)
{
return std::experimental::apply(f, list_to_tuple<TN>(l));
}
void test_compute(int, int, int)
{
// ...
}
int main()
{
list<int> l{};
call_with_list<3>(l, test_compute);
}
How does it work?
The idea is that we "convert" a list to a tuple, specifying how many elements we want to pop from the list at compile-time using list_to_tuple<N>(list).
After getting a tuple from the list, we can use std::experimental::apply to call a function by applying the elements of the tuple as arguments: this is done by call_with_list<N>(list, func).
To create a tuple from the list, two things needs to be done:
Creating an std::tuple<T, T, T, T, ...>, where T is repeated N times.
Call list<T>::pop_back() N times, putting the items in the tuple.
To solve the first problem, decltype is used to get the type of the following variadic expansion: std::make_tuple((TIs, l.pop_back())...). The comma operator is used so that TIs, l.pop_back() evaluates to decltype(l.pop_back()).
To solve the second problem, a variadic expansion is used inside the std::initializer_list tuple constructor, which guarantees order-of-evaluation: return my_tuple{((void)TIs, l.pop_back())...};. The same comma operator "trick" described above is used here.
Can I write it in C++11?
Yes, but it will be slightly more "annoying".
std::experimental::apply is not available: look online for solutions like this one.
std::index_sequence is not available: you will have to implement your own.
template<class T> using void_t = void;
template<class T, class F, std::size_t N=0, class=void>
struct arity:arity<T, F, N+1> {};
template<class F, class T, class Indexes>
struct nary_result_of{};
template<std::size_t, class T>
using ith_T=T;
template<class F, class T, std::size_t...Is>
struct nary_result_of<F, T, std::index_sequence<Is...>>:
std::result_of<F( ith_T<Is, T> )>
{};
template<class T, class F, std::size_t N>
struct arity<T, F, N, void_t<
typename nary_result_of<F, T, std::make_index_sequence<N>>::type
>>:
std::integral_constant<std::size_t, N>
{};
arity uses one C++14 feature (index sequences, easy to write in C++11).
It takes types F and a T and tells you the least number of Ts you can pass to F to make the call valid. If no number of T qualify, it blows your template instantiation stack and your compiler complains or dies.
template<class T>
using strip = typename std::remove_reference<typename std::remove_cv<T>::type>::type;
namespace details {
template<class T, std::size_t N, class F, class R,
std::size_t...Is
>
auto compute( std::index_sequence<Is...>, F&& f, R&& r ) {
std::array<T, N> buff={{
(void(Is), r.pop_back())...
}};
return std::forward<F>(f)( buff[Is]... );
}
}
template<class F, class R,
class T=strip< decltype( *std::declval<R&>().begin() ) >
>
auto compute( F&& f, R&& r ) {
return details::compute( std::make_index_sequence<arity<F,T>{}>{}, std::forward<F>(f), std::forward<R>(r) );
}
The only thing really annoying to convert to C++11 is the auto return type on compute. I'd have to rewrite my arity.
This version should auto detect the arity of even non-function pointers, letting you call this with lambdas or std::functions or what have you.
I'm trying to make this program compile properly:
#include <vector>
#include <iostream>
int f(int a, int b)
{
::std::cout << "f(" << a << ", " << b << ") == " << (a + b) << '\n';
return a + b;
}
template <typename R, typename V>
R bind_vec(R (*f)(), const V &vec, int idx=0)
{
return f();
}
template <typename R, typename V, typename Arg1, typename... ArgT>
R bind_vec(R (*f)(Arg1, ArgT...), const V &vec, int idx=0)
{
const Arg1 &arg = vec[idx];
auto call = [arg, f](ArgT... args) -> R {
return (*f)(arg, args...);
};
return bind_vec(call, vec, idx+1);
}
int foo()
{
::std::vector<int> x = {1, 2};
return bind_vec(f, x);
}
Ideally I'd like bind_vec to take an arbitrary functor as an argument instead of just a function pointer. The idea is to pull the function arguments from a ::std::vector at compile time.
This isn't the final use for this, but it's a stepping stone to where I want to go. What I'm really doing is generating wrapper functions that unwrap their arguments from promises in a future/promise type system at compile time. These wrapper functions will themselves be promises.
In my ultimate use-case I can count on the functors being ::std::functions. But it would be nice to have an idea of how it should work for more general functors as well since I think this is a broadly interesting problem.
OK, first off, detecting the arity of a functor can be done, but it's a bit involved and best left to a separate question. Let's assume you will specify the arity of the functor in the call. Similarly, there are ways to obtain the return type of a callable object, but that's also beyond the scope of this question. Let's just assume the return type is void for now.
So we want to say,
call(F f, C v);
and that should say f(v[0], v[1], ..., v[n-1]), where f has arity n.
Here's an approach:
template <unsigned int N, typename Functor, typename Container>
void call(Functor const & f, Container const & c)
{
call_helper<N == 0, Functor, Container, N>::engage(f, c);
}
We need the helper:
#include <functional>
#include <cassert>
template <bool Done, typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper
{
static void engage(Functor const & f, Container const & c)
{
call_helper<sizeof...(I) + 1 == N, Functor, Container,
N, I..., sizeof...(I)>::engage(f, c);
}
};
template <typename Functor, typename Container,
unsigned int N, unsigned int ...I>
struct call_helper<true, Functor, Container, N, I...>
{
static void engage(Functor const & f, Container const & c)
{
assert(c.size() >= N);
f(c[I]...);
}
};
Example:
#include <vector>
#include <iostream>
void f(int a, int b) { std::cout << "You said: " << a << ", " << b << "\n"; }
struct Func
{
void operator()(int a, int b) const
{ std::cout << "Functor: " << a << "::" << b << "\n"; }
};
int main()
{
std::vector<int> v { 20, 30 };
call<2>(f, v);
call<2>(Func(), v);
}
Notes: In a more advanced version, I would deduce the arity of the callable object with some more template machinery, and I would also deduce the return type. For this to work, you'll need several specializations for free functions and various CV-qualified class member functions, though, and so this would be getting too large for this question.
Something like this is easily possible for (member) function pointers, but for functors with potentially overloaded operator(), this gets a dang lot harder. If we assume that you have a way to tell how many arguments a function takes (and assume that the container actually has that many elements), you can just use the indices trick to expand the vector into an argument list, for example with std::next and a begin() iterator:
#include <utility>
#include <iterator>
template<class F, class Args, unsigned... Is>
auto invoke(F&& f, Args& cont, seq<Is...>)
-> decltype(std::forward<F>(f)(*std::next(cont.begin(), Is)...))
{
return std::forward<F>(f)(*std::next(cont.begin(), Is)...);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
This implementation works really nice for random-access containers, but not so well for forward and especially input ones. To make those work in a performant fashion, you might try to go the route of incrementing the iterator with every expanded step, but you'll run into a problem: Evaluation order of arguments to a function is unspecified, so you'll very likely pass the arguments in the wrong order.
Luckily, there is a way to force evaluation left-to-right: The list-initialization syntax. Now we just need a context where that can be used to pass arguments, and a possible one would be to construct an object, pass the function and the arguments through the constructor, and call the function in there. However, you lose the ability to retrieve the returned value, since constructors can't return a value.
Something I thought of is to create an array of iterators, which point to the correct element, and expanding those again in a second step where they are dereferenced.
#include <utility>
template<class T> using Alias = T; // for temporary arrays
template<class F, class It, unsigned N, unsigned... Is>
auto invoke_2(F&& f, It (&&args)[N], seq<Is...>)
-> decltype(std::forward<F>(f)(*args[Is]...))
{
return std::forward<F>(f)(*args[Is]...);
}
template<class F, class Args, unsigned... Is>
auto invoke_1(F&& f, Args& cont, seq<Is...> s)
-> decltype(invoke_2(std::forward<F>(f), std::declval<decltype(cont.begin())[sizeof...(Is)]>(), s))
{
auto it = cont.begin();
return invoke_2(std::forward<F>(f), Alias<decltype(it)[]>{(void(Is), ++it)...}, s);
}
template<unsigned ArgC, class F, class Args>
auto invoke(F&& f, Args& cont)
-> decltype(invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{}))
{
return invoke_1(std::forward<F>(f), cont, gen_seq<ArgC>{});
}
The code was tested against GCC 4.7.2 and works as advertised.
Since you said that the functors you are getting passed are std::functions, getting the number of arguments they take is really easy:
template<class F> struct function_arity;
// if you have the 'Signature' of a 'std::function' handy
template<class R, class... Args>
struct function_arity<R(Args...)>
: std::integral_constant<std::size_t, sizeof...(Args)>{};
// if you only have the 'std::function' available
template<class R, class... Args>
struct function_arity<std::function<R(Args...)>>
: function_arity<R(Args...)>{};
Note that you don't even need function_arity to make invoke from above work for std::function:
template<class R, class... Ts, class Args>
R invoke(std::function<R(Ts...)> const& f, Args& cont){
return invoke_1(f, cont, gen_seq<sizeof...(Ts)>{})
}
I managed to do what you want. It's simplest to explain if I leave it as not deducing the correct return type at first, I'll show how to add that later on:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),void>::type
{
f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),void>::type
{
bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}
There are two versions of this bind_vec - one is enabled if the parameter pack is the right size for the function. The other is enabled if it is still too small. The first version simply dispatches the call using the parameter pack, whilst the second version gets the next element (as determined by the size of the parameter pack) and recurses.
There SFINAE is done on the return type of the function in order that it not interfer with the deduction of the types, but this means it needs to be done after the function since it needs to know about F. There's a helper function that finds the number of arguments needed to call a function pointer.
To deduce the return types also we can use decltype with the function pointer:
#include <vector>
#include <type_traits>
namespace {
int f(int a, int b) { return 0; }
}
template <typename ...Args>
constexpr unsigned nb_args(int (*)(Args...)) {
return sizeof...(Args);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V&, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) == nb_args(F()),decltype(f(std::forward<Args>(args)...))>::type
{
return f(std::forward<Args>(args)...);
}
template <typename F, typename V, typename ...Args>
auto bind_vec(F f, const V& v, Args&& ...args)
-> typename std::enable_if<sizeof...(Args) < nb_args(F()),decltype(bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args))))>::type
{
return bind_vec(f, v, std::forward<Args>(args)..., v.at(sizeof...(Args)));
}
int main() {
bind_vec(&f, std::vector<int>(), 1);
return 0;
}
What is currying?
How can currying be done in C++?
Please Explain binders in STL container?
1. What is currying?
Currying simply means a transformation of a function of several arguments to a function of a single argument. This is most easily illustrated using an example:
Take a function f that accepts three arguments:
int
f(int a,std::string b,float c)
{
// do something with a, b, and c
return 0;
}
If we want to call f, we have to provide all of its arguments f(1,"some string",19.7f).
Then a curried version of f, let's call it curried_f=curry(f) only expects a single argument, that corresponds to the first argument of f, namely the argument a. Additionally, f(1,"some string",19.7f) can also be written using the curried version as curried_f(1)("some string")(19.7f). The return value of curried_f(1) on the other hand is just another function, that handles the next argument of f. In the end, we end up with a function or callable curried_f that fulfills the following equality:
curried_f(first_arg)(second_arg)...(last_arg) == f(first_arg,second_arg,...,last_arg).
2. How can currying be achieved in C++?
The following is a little bit more complicated, but works very well for me (using c++11)... It also allows currying of arbitrary degree like so: auto curried=curry(f)(arg1)(arg2)(arg3) and later auto result=curried(arg4)(arg5). Here it goes:
#include <functional>
namespace _dtl {
template <typename FUNCTION> struct
_curry;
// specialization for functions with a single argument
template <typename R,typename T> struct
_curry<std::function<R(T)>> {
using
type = std::function<R(T)>;
const type
result;
_curry(type fun) : result(fun) {}
};
// recursive specialization for functions with more arguments
template <typename R,typename T,typename...Ts> struct
_curry<std::function<R(T,Ts...)>> {
using
remaining_type = typename _curry<std::function<R(Ts...)> >::type;
using
type = std::function<remaining_type(T)>;
const type
result;
_curry(std::function<R(T,Ts...)> fun)
: result (
[=](const T& t) {
return _curry<std::function<R(Ts...)>>(
[=](const Ts&...ts){
return fun(t, ts...);
}
).result;
}
) {}
};
}
template <typename R,typename...Ts> auto
curry(const std::function<R(Ts...)> fun)
-> typename _dtl::_curry<std::function<R(Ts...)>>::type
{
return _dtl::_curry<std::function<R(Ts...)>>(fun).result;
}
template <typename R,typename...Ts> auto
curry(R(* const fun)(Ts...))
-> typename _dtl::_curry<std::function<R(Ts...)>>::type
{
return _dtl::_curry<std::function<R(Ts...)>>(fun).result;
}
#include <iostream>
void
f(std::string a,std::string b,std::string c)
{
std::cout << a << b << c;
}
int
main() {
curry(f)("Hello ")("functional ")("world!");
return 0;
}
View output
OK, as Samer commented, I should add some explanations as to how this works. The actual implementation is done in the _dtl::_curry, while the template functions curry are only convenience wrappers. The implementation is recursive over the arguments of the std::function template argument FUNCTION.
For a function with only a single argument, the result is identical to the original function.
_curry(std::function<R(T,Ts...)> fun)
: result (
[=](const T& t) {
return _curry<std::function<R(Ts...)>>(
[=](const Ts&...ts){
return fun(t, ts...);
}
).result;
}
) {}
Here the tricky thing: For a function with more arguments, we return a lambda whose argument is bound to the first argument to the call to fun. Finally, the remaining currying for the remaining N-1 arguments is delegated to the implementation of _curry<Ts...> with one less template argument.
Update for c++14 / 17:
A new idea to approach the problem of currying just came to me... With the introduction of if constexpr into c++17 (and with the help of void_t to determine if a function is fully curried), things seem to get a lot easier:
template< class, class = std::void_t<> > struct
needs_unapply : std::true_type { };
template< class T > struct
needs_unapply<T, std::void_t<decltype(std::declval<T>()())>> : std::false_type { };
template <typename F> auto
curry(F&& f) {
/// Check if f() is a valid function call. If not we need
/// to curry at least one argument:
if constexpr (needs_unapply<decltype(f)>::value) {
return [=](auto&& x) {
return curry(
[=](auto&&...xs) -> decltype(f(x,xs...)) {
return f(x,xs...);
}
);
};
}
else {
/// If 'f()' is a valid call, just call it, we are done.
return f();
}
}
int
main()
{
auto f = [](auto a, auto b, auto c, auto d) {
return a * b * c * d;
};
return curry(f)(1)(2)(3)(4);
}
See code in action on here. With a similar approach, here is how to curry functions with arbitrary number of arguments.
The same idea seems to work out also in C++14, if we exchange the constexpr if with a template selection depending on the test needs_unapply<decltype(f)>::value:
template <typename F> auto
curry(F&& f);
template <bool> struct
curry_on;
template <> struct
curry_on<false> {
template <typename F> static auto
apply(F&& f) {
return f();
}
};
template <> struct
curry_on<true> {
template <typename F> static auto
apply(F&& f) {
return [=](auto&& x) {
return curry(
[=](auto&&...xs) -> decltype(f(x,xs...)) {
return f(x,xs...);
}
);
};
}
};
template <typename F> auto
curry(F&& f) {
return curry_on<needs_unapply<decltype(f)>::value>::template apply(f);
}
In short, currying takes a function f(x, y) and given a fixed Y, gives a new function g(x) where
g(x) == f(x, Y)
This new function may be called in situations where only one argument is supplied, and passes the call on to the original f function with the fixed Y argument.
The binders in the STL allow you to do this for C++ functions. For example:
#include <functional>
#include <iostream>
#include <vector>
using namespace std;
// declare a binary function object
class adder: public binary_function<int, int, int> {
public:
int operator()(int x, int y) const
{
return x + y;
}
};
int main()
{
// initialise some sample data
vector<int> a, b;
a.push_back(1);
a.push_back(2);
a.push_back(3);
// here we declare a function object f and try it out
adder f;
cout << "f(2, 3) = " << f(2, 3) << endl;
// transform() expects a function with one argument, so we use
// bind2nd to make a new function based on f, that takes one
// argument and adds 5 to it
transform(a.begin(), a.end(), back_inserter(b), bind2nd(f, 5));
// output b to see what we got
cout << "b = [" << endl;
for (vector<int>::iterator i = b.begin(); i != b.end(); ++i) {
cout << " " << *i << endl;
}
cout << "]" << endl;
return 0;
}
Simplifying Gregg's example, using tr1:
#include <functional>
using namespace std;
using namespace std::tr1;
using namespace std::tr1::placeholders;
int f(int, int);
..
int main(){
function<int(int)> g = bind(f, _1, 5); // g(x) == f(x, 5)
function<int(int)> h = bind(f, 2, _1); // h(x) == f(2, x)
function<int(int,int)> j = bind(g, _2); // j(x,y) == g(y)
}
Tr1 functional components allow you to write rich functional-style code in C++. As well, C++0x will allow for in-line lambda functions to do this as well:
int f(int, int);
..
int main(){
auto g = [](int x){ return f(x,5); }; // g(x) == f(x, 5)
auto h = [](int x){ return f(2,x); }; // h(x) == f(2, x)
auto j = [](int x, int y){ return g(y); }; // j(x,y) == g(y)
}
And while C++ doesn't provide the rich side-effect analysis that some functional-oriented programming languages perform, const analysis and C++0x lambda syntax can help:
struct foo{
int x;
int operator()(int y) const {
x = 42; // error! const function can't modify members
}
};
..
int main(){
int x;
auto f = [](int y){ x = 42; }; // error! lambdas don't capture by default.
}
Hope that helps.
Have a look at Boost.Bind which makes the process shown by Greg more versatile:
transform(a.begin(), a.end(), back_inserter(b), bind(f, _1, 5));
This binds 5 to f's second argument.
It’s worth noting that this is not currying (instead, it’s partial application). However, using currying in a general way is hard in C++ (in fact, it only recently became possible at all) and partial application is often used instead.
Other answers nicely explain binders, so I won't repeat that part here. I will only demonstrate how currying and partial application can be done with lambdas in C++0x.
Code example: (Explanation in comments)
#include <iostream>
#include <functional>
using namespace std;
const function<int(int, int)> & simple_add =
[](int a, int b) -> int {
return a + b;
};
const function<function<int(int)>(int)> & curried_add =
[](int a) -> function<int(int)> {
return [a](int b) -> int {
return a + b;
};
};
int main() {
// Demonstrating simple_add
cout << simple_add(4, 5) << endl; // prints 9
// Demonstrating curried_add
cout << curried_add(4)(5) << endl; // prints 9
// Create a partially applied function from curried_add
const auto & add_4 = curried_add(4);
cout << add_4(5) << endl; // prints 9
}
If you're using C++14 it's very easy:
template<typename Function, typename... Arguments>
auto curry(Function function, Arguments... args) {
return [=](auto... rest) {
return function(args..., rest...);
}; // don't forget semicolumn
}
You can then use it like this:
auto add = [](auto x, auto y) { return x + y; }
// curry 4 into add
auto add4 = curry(add, 4);
add4(6); // 10
Some great answers here. I thought I would add my own because it was fun to play around with the concept.
Partial function application: The process of "binding" a function with only some of its parameters, deferring the rest to be filled in later. The result is another function with fewer parameters.
Currying: Is a special form of partial function application where you can only "bind" a single argument at a time. The result is another function with exactly 1 fewer parameter.
The code I'm about to present is partial function application from which currying is possible, but not the only possibility. It offers a few benefits over the above currying implementations (mainly because it's partial function application and not currying, heh).
Applying over an empty function:
auto sum0 = [](){return 0;};
std::cout << partial_apply(sum0)() << std::endl;
Applying multiple arguments at a time:
auto sum10 = [](int a, int b, int c, int d, int e, int f, int g, int h, int i, int j){return a+b+c+d+e+f+g+h+i+j;};
std::cout << partial_apply(sum10)(1)(1,1)(1,1,1)(1,1,1,1) << std::endl; // 10
constexpr support that allows for compile-time static_assert:
static_assert(partial_apply(sum0)() == 0);
A useful error message if you accidentally go too far in providing arguments:
auto sum1 = [](int x){ return x;};
partial_apply(sum1)(1)(1);
error: static_assert failed "Attempting to apply too many arguments!"
Other answers above return lambdas that bind an argument and then return further lambdas. This approach wraps that essential functionality into a callable object. Definitions for operator() allow the internal lambda to be called. Variadic templates allow us to check for someone going too far, and an implicit conversion function to the result type of the function call allows us to print the result or compare the object to a primitive.
Code:
namespace detail{
template<class F>
using is_zero_callable = decltype(std::declval<F>()());
template<class F>
constexpr bool is_zero_callable_v = std::experimental::is_detected_v<is_zero_callable, F>;
}
template<class F>
struct partial_apply_t
{
template<class... Args>
constexpr auto operator()(Args... args)
{
static_assert(sizeof...(args) == 0 || !is_zero_callable, "Attempting to apply too many arguments!");
auto bind_some = [=](auto... rest) -> decltype(myFun(args..., rest...))
{
return myFun(args..., rest...);
};
using bind_t = decltype(bind_some);
return partial_apply_t<bind_t>{bind_some};
}
explicit constexpr partial_apply_t(F fun) : myFun(fun){}
constexpr operator auto()
{
if constexpr (is_zero_callable)
return myFun();
else
return *this; // a callable
}
static constexpr bool is_zero_callable = detail::is_zero_callable_v<F>;
F myFun;
};
Live Demo
A few more notes:
I chose to use is_detected mainly for enjoyment and practice; it serves the same as a normal type trait would here.
There could definitely be more work done to support perfect forwarding for performance reasons
The code is C++17 because it requires for constexpr lambda support in C++17
And it seems that GCC 7.0.1 is not quite there yet, either, so I used Clang 5.0.0
Some tests:
auto sum0 = [](){return 0;};
auto sum1 = [](int x){ return x;};
auto sum2 = [](int x, int y){ return x + y;};
auto sum3 = [](int x, int y, int z){ return x + y + z; };
auto sum10 = [](int a, int b, int c, int d, int e, int f, int g, int h, int i, int j){return a+b+c+d+e+f+g+h+i+j;};
std::cout << partial_apply(sum0)() << std::endl; //0
static_assert(partial_apply(sum0)() == 0, "sum0 should return 0");
std::cout << partial_apply(sum1)(1) << std::endl; // 1
std::cout << partial_apply(sum2)(1)(1) << std::endl; // 2
std::cout << partial_apply(sum3)(1)(1)(1) << std::endl; // 3
static_assert(partial_apply(sum3)(1)(1)(1) == 3, "sum3 should return 3");
std::cout << partial_apply(sum10)(1)(1,1)(1,1,1)(1,1,1,1) << std::endl; // 10
//partial_apply(sum1)(1)(1); // fails static assert
auto partiallyApplied = partial_apply(sum3)(1)(1);
std::function<int(int)> finish_applying = partiallyApplied;
std::cout << std::boolalpha << (finish_applying(1) == 3) << std::endl; // true
auto plus2 = partial_apply(sum3)(1)(1);
std::cout << std::boolalpha << (plus2(1) == 3) << std::endl; // true
std::cout << std::boolalpha << (plus2(3) == 5) << std::endl; // true
Currying is a way of reducing a function that takes multiple arguments into a sequence of nested functions with one argument each:
full = (lambda a, b, c: (a + b + c))
print full (1, 2, 3) # print 6
# Curried style
curried = (lambda a: (lambda b: (lambda c: (a + b + c))))
print curried (1)(2)(3) # print 6
Currying is nice because you can define functions that are simply wrappers around other functions with pre-defined values, and then pass around the simplified functions. C++ STL binders provide an implementation of this in C++.
I implemented currying with variadic templates as well (see Julian's answer). However, I did not make use of recursion or std::function. Note: It uses a number of C++14 features.
The provided example (main function) actually runs at compile time, proving that the currying method does not trump essential optimizations by the compiler.
The code can be found here: https://gist.github.com/Garciat/c7e4bef299ee5c607948
with this helper file: https://gist.github.com/Garciat/cafe27d04cfdff0e891e
The code still needs (a lot of) work, which I may or may not complete soon. Either way, I'm posting this here for future reference.
Posting code in case links die (though they shouldn't):
#include <type_traits>
#include <tuple>
#include <functional>
#include <iostream>
// ---
template <typename FType>
struct function_traits;
template <typename RType, typename... ArgTypes>
struct function_traits<RType(ArgTypes...)> {
using arity = std::integral_constant<size_t, sizeof...(ArgTypes)>;
using result_type = RType;
template <size_t Index>
using arg_type = typename std::tuple_element<Index, std::tuple<ArgTypes...>>::type;
};
// ---
namespace details {
template <typename T>
struct function_type_impl
: function_type_impl<decltype(&T::operator())>
{ };
template <typename RType, typename... ArgTypes>
struct function_type_impl<RType(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename RType, typename... ArgTypes>
struct function_type_impl<RType(*)(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename RType, typename... ArgTypes>
struct function_type_impl<std::function<RType(ArgTypes...)>> {
using type = RType(ArgTypes...);
};
template <typename T, typename RType, typename... ArgTypes>
struct function_type_impl<RType(T::*)(ArgTypes...)> {
using type = RType(ArgTypes...);
};
template <typename T, typename RType, typename... ArgTypes>
struct function_type_impl<RType(T::*)(ArgTypes...) const> {
using type = RType(ArgTypes...);
};
}
template <typename T>
struct function_type
: details::function_type_impl<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
{ };
// ---
template <typename Args, typename Params>
struct apply_args;
template <typename HeadArgs, typename... Args, typename HeadParams, typename... Params>
struct apply_args<std::tuple<HeadArgs, Args...>, std::tuple<HeadParams, Params...>>
: std::enable_if<
std::is_constructible<HeadParams, HeadArgs>::value,
apply_args<std::tuple<Args...>, std::tuple<Params...>>
>::type
{ };
template <typename... Params>
struct apply_args<std::tuple<>, std::tuple<Params...>> {
using type = std::tuple<Params...>;
};
// ---
template <typename TupleType>
struct is_empty_tuple : std::false_type { };
template <>
struct is_empty_tuple<std::tuple<>> : std::true_type { };
// ----
template <typename FType, typename GivenArgs, typename RestArgs>
struct currying;
template <typename FType, typename... GivenArgs, typename... RestArgs>
struct currying<FType, std::tuple<GivenArgs...>, std::tuple<RestArgs...>> {
std::tuple<GivenArgs...> given_args;
FType func;
template <typename Func, typename... GivenArgsReal>
constexpr
currying(Func&& func, GivenArgsReal&&... args) :
given_args(std::forward<GivenArgsReal>(args)...),
func(std::move(func))
{ }
template <typename... Args>
constexpr
auto operator() (Args&&... args) const& {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CanExecute = is_empty_tuple<RestArgsPrime>;
return apply(CanExecute{}, std::make_index_sequence<sizeof...(GivenArgs)>{}, std::forward<Args>(args)...);
}
template <typename... Args>
constexpr
auto operator() (Args&&... args) && {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CanExecute = is_empty_tuple<RestArgsPrime>;
return std::move(*this).apply(CanExecute{}, std::make_index_sequence<sizeof...(GivenArgs)>{}, std::forward<Args>(args)...);
}
private:
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::false_type, std::index_sequence<Indices...>, Args&&... args) const& {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CurryType = currying<FType, std::tuple<GivenArgs..., Args...>, RestArgsPrime>;
return CurryType{ func, std::get<Indices>(given_args)..., std::forward<Args>(args)... };
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::false_type, std::index_sequence<Indices...>, Args&&... args) && {
using ParamsTuple = std::tuple<RestArgs...>;
using ArgsTuple = std::tuple<Args...>;
using RestArgsPrime = typename apply_args<ArgsTuple, ParamsTuple>::type;
using CurryType = currying<FType, std::tuple<GivenArgs..., Args...>, RestArgsPrime>;
return CurryType{ std::move(func), std::get<Indices>(std::move(given_args))..., std::forward<Args>(args)... };
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::true_type, std::index_sequence<Indices...>, Args&&... args) const& {
return func(std::get<Indices>(given_args)..., std::forward<Args>(args)...);
}
template <typename... Args, size_t... Indices>
constexpr
auto apply(std::true_type, std::index_sequence<Indices...>, Args&&... args) && {
return func(std::get<Indices>(std::move(given_args))..., std::forward<Args>(args)...);
}
};
// ---
template <typename FType, size_t... Indices>
constexpr
auto curry(FType&& func, std::index_sequence<Indices...>) {
using RealFType = typename function_type<FType>::type;
using FTypeTraits = function_traits<RealFType>;
using CurryType = currying<FType, std::tuple<>, std::tuple<typename FTypeTraits::template arg_type<Indices>...>>;
return CurryType{ std::move(func) };
}
template <typename FType>
constexpr
auto curry(FType&& func) {
using RealFType = typename function_type<FType>::type;
using FTypeArity = typename function_traits<RealFType>::arity;
return curry(std::move(func), std::make_index_sequence<FTypeArity::value>{});
}
// ---
int main() {
auto add = curry([](int a, int b) { return a + b; });
std::cout << add(5)(10) << std::endl;
}
These Links are relevant:
The Lambda Calculus page on Wikipedia has a clear example of currying
http://en.wikipedia.org/wiki/Lambda_calculus#Motivation
This paper treats currying in C/C++
http://asg.unige.ch/site/papers/Dami91a.pdf
C++20 provides bind_front for doing currying.
For older C++ version it can be implemented (for single argument) as follows:
template <typename TFunc, typename TArg>
class CurryT
{
private:
TFunc func;
TArg arg ;
public:
template <typename TFunc_, typename TArg_>
CurryT(TFunc_ &&func, TArg_ &&arg)
: func(std::forward<TFunc_>(func))
, arg (std::forward<TArg_ >(arg ))
{}
template <typename... TArgs>
auto operator()(TArgs &&...args) const
-> decltype( func(arg, std::forward<TArgs>(args)...) )
{ return func(arg, std::forward<TArgs>(args)...); }
};
template <typename TFunc, typename TArg>
CurryT<std::decay_t<TFunc>, std::remove_cv_t<TArg>> Curry(TFunc &&func, TArg &&arg)
{ return {std::forward<TFunc>(func), std::forward<TArg>(arg)}; }
https://coliru.stacked-crooked.com/a/82856e39da5fa50d
void Abc(std::string a, int b, int c)
{
std::cerr << a << b << c << std::endl;
}
int main()
{
std::string str = "Hey";
auto c1 = Curry(Abc, str);
std::cerr << "str: " << str << std::endl;
c1(1, 2);
auto c2 = Curry(std::move(c1), 3);
c2(4);
auto c3 = Curry(c2, 5);
c3();
}
Output:
str:
Hey12
Hey34
Hey35
If you use long chains of currying then std::shared_ptr optimization can be used to avoid copying all previous curried parameters to each new carried function.
template <typename TFunc>
class SharedFunc
{
public:
struct Tag{}; // For avoiding shadowing copy/move constructors with the
// templated constructor below which accepts any parameters.
template <typename... TArgs>
SharedFunc(Tag, TArgs &&...args)
: p_func( std::make_shared<TFunc>(std::forward<TArgs>(args)...) )
{}
template <typename... TArgs>
auto operator()(TArgs &&...args) const
-> decltype( (*p_func)(std::forward<TArgs>(args)...) )
{ return (*p_func)(std::forward<TArgs>(args)...); }
private:
std::shared_ptr<TFunc> p_func;
};
template <typename TFunc, typename TArg>
SharedFunc<
CurryT<std::decay_t<TFunc>, std::remove_cv_t<TArg>>
>
CurryShared(TFunc &&func, TArg &&arg)
{
return { {}, std::forward<TFunc>(func), std::forward<TArg>(arg) };
}
https://coliru.stacked-crooked.com/a/6e71f41e1cc5fd5c