Improving fold function - c++

I have implemented a simple fold function in C++ that accepts a lambda, and can fold multiple vectors at the same time at compile time. I am wondering if it could be simplified in some manner (I have provided both a recursive version and an iteratively recursive version - I am unsure which should have better performance): https://godbolt.org/z/39pW81
Performance optimizations are also welcome - in that regard is any of the two approaches faster?
template<int I, typename type_identity, typename type_head, int N, typename ...type_tail, int ...N_tail, typename Function>
auto foldHelperR(Function&& func, const type_identity& id, const tvecn<type_head, N>& head, const tvecn<type_tail, N_tail>&... tail)
{
if constexpr (I>0)
{
return func(foldHelperR<I-1>(std::forward<Function>(func), id, head, tail...), head[I], tail[I]...);
}
else
{
return func(id, head[0], tail[0]...);
}
}
template<int I, typename type_identity, typename type_head, int N, typename ...type_tail, int ...N_tail, typename Function>
auto foldHelperI(Function&& func, const type_identity id, const tvecn<type_head, N>& head, const tvecn<type_tail, N_tail>&... tail)
{
if constexpr (I<N-1)
{
return foldHelperI<I+1>(std::forward<Function>(func), func(id, head[I], tail[I]...), head, tail...);
}
else
{
return func(id, head[N-1], tail[N-1]...);
}
}
template<typename type_identity, typename type_head, int N_head, typename ...type_tail, int ...N_tail, typename Function = void (const type_identity&, const type_head&, const type_tail&...)>
constexpr auto fold(Function&& func, const type_identity& id, const tvecn<type_head, N_head>& head, const tvecn<type_tail, N_tail>&... tail)
{
static_assert(std::is_invocable_v<Function, const type_identity&, const type_head&, const type_tail &...>,
"The function cannot be invoked with these zip arguments (possibly wrong argument count).");
static_assert(all_equal_v<N_head, N_tail...>, "Vector sizes must match.");
//return foldHelperR<N_head-1>(std::forward<Function>(func), id, head, tail...);
return foldHelperI<0>(std::forward<Function>(func), id, head, tail...);
}
int main()
{
tvecn<int,3> a(1,2,3);
return fold([](auto x, auto y, auto z) {return x+y+z;}, 0, a, a);
}

and can fold multiple vectors at the same time at compile time
Not exactly: if you want to operate compile-time
(1) you have to define constexpr the tvecn constructor and
(2) you have to define constexpr the foldhelper function and
(3) you have to declare constexpr a
// VVVVVVVVV
constexpr tvecn<int,3> a(1,2,3);
(4) you have to place the result of fold in a constexpr variable (or, more generally speaking, in a place where the value is required compile time, as the size field of a C-style array, or a template value parameter, or a static_assert() test)
constexpr auto f = fold([](auto x, auto y, auto z) {return x+y+z;},
0, a, a);
I am wondering if it could be simplified in some manner
Sure.
First of all: if you can, avoid to reinventing the weel: your tvecn is a simplified version of std::array.
Suggestion: use std::array (if you can obviously)
Second: you tagged C++17 so you can use folding
Suggestion: use it also for all_equal
template <auto V0, auto ... Vs>
struct all_equal : public std::bool_constant<((V0 == Vs) && ...)>
{ };
template<auto ...N_pack>
constexpr bool all_equal_v = all_equal<N_pack...>::value;
More in general: when you have to define a custom type traits that has to provide a number, inherit (if possible) from std::integral_constant (or std::bool_constant, or std::true_type, or std::false_type: all std::integral_constant specializations). So you automatically inherit all std::integral_constant facilities.
Third: almost all C++ standard uses std::size_t, not int, for sizes.
Suggestion: when you have to do with sizes, use std::size_t, not int. This way you can avoid a lot of annoying troubles.
Fourth: from main() you should return only EXIT_SUCCESS (usually zero) or EXIT_FAILURE (usually 1)
Suggestion: avoid things as
return fold([](auto x, auto y, auto z) {return x+y+z;}, 0, a, a);
Fifth: never underestimate the power of the comma operator.
Suggestion: avoid recursion at all and use template folding also for the helper function; by example
template <std::size_t ... Is, typename F, typename T, typename ... As>
constexpr auto foldHelperF (std::index_sequence<Is...>,
F const & f, T id, As const & ... arrs)
{ return ( ..., (id = [&](auto i){ return f(id, arrs[i]...); }(Is))); }
that you can call as follows from fold()
return foldHelperF(std::make_index_sequence<N_head>{},
std::forward<Function>(func),
id, head, tail...);
The following is a full compiling, and simplified, example
#include <array>
#include <utility>
#include <iostream>
#include <type_traits>
template <auto V0, auto ... Vs>
struct all_equal : public std::bool_constant<((V0 == Vs) && ...)>
{ };
template<auto ...N_pack>
constexpr bool all_equal_v = all_equal<N_pack...>::value;
template <std::size_t ... Is, typename F, typename T, typename ... As>
constexpr auto foldHelperF (std::index_sequence<Is...>,
F const & f, T id, As const & ... arrs)
{ return ( ..., (id = [&](auto i){ return f(id, arrs[i]...); }(Is))); }
template <typename type_identity, typename type_head, std::size_t N_head,
typename ...type_tail, std::size_t ...N_tail,
typename Function = void (type_identity const &,
type_head const &,
type_tail const & ...)>
constexpr auto fold (Function && func, type_identity const & id,
std::array<type_head, N_head> const & head,
std::array<type_tail, N_tail> const & ... tail)
{
static_assert( std::is_invocable_v<Function, const type_identity&,
const type_head&, const type_tail &...>,
"The function cannot be invoked with these zip arguments"
" (possibly wrong argument count).");
static_assert( all_equal_v<N_head, N_tail...>,
"Vector sizes must match.");
return foldHelperF(std::make_index_sequence<N_head>{},
std::forward<Function>(func),
id, head, tail...);
}
int main()
{
constexpr std::array<int, 3u> b{2, 5, 7};
constexpr auto f = fold([](auto x, auto y, auto z) {return x+y+z;},
0, b, b);
std::cout << f << std::endl;
}

With Fold expression, it might be:
template <typename F, typename Init, std::size_t... Is, typename... Arrays>
constexpr auto fold_impl(F&& f, Init init, std::index_sequence<Is...>, Arrays&&... arrays)
{
auto l = [&](Init init, std::size_t i){ return f(init, arrays[i]...); };
return ((init = l(init, Is)), ...);
}
template <typename F, typename Init, typename Array, typename ... Arrays>
constexpr auto fold(F&& f, Init init, Array&& array, Arrays&&... arrays)
{
static_assert(((arrays.size() == array.size()) && ...));
return fold_impl(f, init, std::make_index_sequence<array.size()>{}, array, arrays...);
}
Demo

Related

Differentiate between two pack expansions

Is there a way to explicitly specify which ... refers to which pack expansion? In my code I have two pack expansions that I want to apply at different levels:
template<typename T, int N>
struct MyArr
{
T e[N];
constexpr T& operator[](int i) { return e[i]; }
constexpr const T& operator[](int i) const { return e[i]; }
MyArr() : e{} {}
template<typename ...type_pack>
MyArr(const type_pack&... pack) : e{pack...}
{
static_assert(sizeof...(pack)==N,
"Argument count must match the size.");
}
};
template<typename type_lhs, typename type_rhs>
auto add(const type_lhs& lhs, const type_rhs& rhs)
{
return lhs + rhs;
}
template<int ...I, typename type_head, typename ...type_pack, int N, typename Function>
auto apply(Function&& op,
const MyArr<type_head,N>& head, const MyArr<type_pack,N>&... pack)
{
return MyArr<type_head,N>((op(head[I],(pack[I])...))...);
// expand pack[I]- ^ , ^ - expand I...
};
int main()
{
MyArr<int,3> a(1,2,3);
return apply<0,1,2>(add<int,int>, a, a);
}
Essentially, I want to get:
(op(head[0], get<0>(pack)[0], ..., get<M-1>(pack)[0]),
...,
op(head[N-1], get<0>(pack)[N-1], ..., get<M-1>(pack)[N-1]))
Thanks to OznOg's advice I got it to work through creating a function in the middle:
template<int ...I, typename type_head, typename ...type_pack, int N, typename Function>
auto apply(Function&& op,
const MyArr<type_head,N>& head, const MyArr<type_pack,N>&... pack)
{
auto op2 = [&](int i) { return op(head[i], pack[i]...);};
return MyArr<type_head,N>(op2(I)...);
};
In this particular case, the only way I see is the use of an helper function (getVal(), in the following example)
template <int I, typename type_head, typename ...type_pack, int N,
typename Function>
auto getVal (Function&& op, MyArr<type_head,N> const & head,
MyArr<type_pack,N> const & ... pack)
{ return op(head[I], pack[I]...); }
template <int ... Is, typename type_head, typename ...type_pack, int N,
typename Function>
auto apply (Function && op, MyArr<type_head,N> const & head,
MyArr<type_pack,N> const &... pack)
{ return MyArr<type_head,N>{ getVal<Is>(op, head, pack...)... }; }
The problem is that you have
(pack[I])...
so there is no way (as far I know) to say that the expansion is to be applied to pack and not to I.
With the intermediate function
//.......................VVV expand pack
getVal<Is>(op, head, pack...)...
//...........................^^^ expand Is
you can use parentheses to separate the levels.
But you have to separate pack and Is.

How can I map a C++ parameter pack into a sequence of std::pair objects?

I have a variadic template function foo():
template <typename... Args>
void foo(Args &&... args);
This function is intended to be invoked with all arguments of size_t. I can enforce that using some metaprogramming. I need to take the resulting list of arguments two at a time and put them into a container of std::pair<size_t, size_t>. Conceptually, something like:
std::vector<std::pair<size_t, size_t> > = {
std::make_pair(args[0], args[1]),
std::make_pair(args[2], args[3]), ...
};
Is there a straightforward way to do this? I know that by pack expansion, I could put the arguments into a flat container, but is there a way to group them two by two into std::pair objects at the same time?
Indexing into packs isn't really doable (yet?), but indexing into tuples is. Just stick everything into a tuple first, and then pull everything back out as you go. Since everything's a size_t, we can just copy:
template <size_t... Is, class Tuple>
std::vector<std::pair<size_t, size_t>>
foo_impl(std::index_sequence<Is...>, Tuple tuple) {
return std::vector<std::pair<size_t, size_t> >{
std::make_pair(std::get<2*Is>(tuple), std::get<2*Is+1>(tuple))...
};
}
template <typename... Args>
void foo(Args... args)
{
auto vs = foo_impl(std::make_index_sequence<sizeof...(Args)/2>{},
std::make_tuple(args...));
// ...
}
Suppose you are allowed to refactor your logic into an internal helper function:
template <typename ...Args>
void foo(Args &&... args)
{
foo_impl(std::make_index_sequence<sizeof...(Args) / 2>(),
std::forward<Args>(args)...);
}
Now we can operate on the argument pack index by index:
template <std::size_t ...I, typename ...Args>
void foo_impl(std::index_sequence<I...>, Args &&... args)
{
std::vector<std::pair<std::size_t, std::size_t>> v =
{ GetPair(std::integral_constant<std::size_t, I>(), args...)... };
}
It remains to implement the pair extractor:
template <typename A, typename B, typename ...Tail>
std::pair<std::size_t, std::size_t> GetPair(std::integral_constant<std::size_t, 0>,
A a, B b, Tail ... tail)
{
return { a, b };
}
template <std::size_t I, typename A, typename B, typename ...Tail>
std::pair<std::size_t, std::size_t> GetPair(std::integral_constant<std::size_t, I>,
A a, B b, Tail ... tail)
{
return GetPair<I - 1>(tail...);
}
With range-v3, you may do
template <typename... Args>
void foo(Args&&... args)
{
std::initializer_list<std::size_t> nbs = {static_cast<std::size_t>(args)...};
const auto pair_view =
ranges::view::zip(nbs | ranges::view::stride(2),
nbs | ranges::view::drop(1) | ranges::view::stride(2));
// And possibly
std::vector<std::pair<std::size_t, std::size_t>> pairs = pair_view;
// ...
}
Demo
Someone (cough #Barry cough) said that indexing into packs isn't possible.
This is C++. Impossible means we just haven't written it yet.
template<std::size_t I> struct index_t:std::integral_constant<std::size_t, I> {
using std::integral_constant<std::size_t, I>::integral_constant;
template<std::size_t J>
constexpr index_t<I+J> operator+( index_t<J> ) const { return {}; }
template<std::size_t J>
constexpr index_t<I-J> operator-( index_t<J> ) const { return {}; }
template<std::size_t J>
constexpr index_t<I*J> operator*( index_t<J> ) const { return {}; }
template<std::size_t J>
constexpr index_t<I/J> operator/( index_t<J> ) const { return {}; }
};
template<std::size_t I>
constexpr index_t<I> index{};
template<std::size_t B>
constexpr index_t<1> exponent( index_t<B>, index_t<0> ) { return {}; }
template<std::size_t B, std::size_t E>
constexpr auto exponent( index_t<B>, index_t<E> ) {
return index<B> * exponent( index<B>, index<E-1> );
}
template<std::size_t N>
constexpr index_t<0> from_base(index_t<N>) { return {}; }
template<std::size_t N, std::size_t c>
constexpr index_t<c-'0'> from_base(index_t<N>, index_t<c>) { return {}; }
template<std::size_t N, std::size_t c0, std::size_t...cs>
constexpr auto from_base(index_t<N>, index_t<c0>, index_t<cs>...) {
return
from_base(index<N>, index<c0>) * exponent(index<N>, index<sizeof...(cs)>)
+ from_base(index<N>, index<cs>...)
;
}
template<char...cs>
constexpr auto operator""_idx(){
return from_base(index<10>, index<cs>...);
}
auto nth = [](auto index_in){
return [](auto&&...elems)->decltype(auto){
using std::get;
constexpr auto I= index<decltype(index_in){}>;
return get<I>(std::forward_as_tuple(decltype(elems)(elems)...));
};
};
Now we get:
using pair_vec = std::vector<std::pair<std::size_t, std::size_t>>;
template <typename... Args>
pair_vec foo(Args &&... args) {
return
index_over< sizeof...(args)/2 >()
([&](auto...Is)->pair_vec{
return {
{
nth( Is*2_idx )( decltype(args)(args)... ),
nth( Is*2_idx+1_idx )( decltype(args)(args)... )
}...
};
});
}
where we "directly" index into our parameter packs using compile time constant indexes.
live example.

How to metaprogram a generic list extraction for building a function call

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.

Cannot remove unwanted overloads

The function transform conducted by
const std::vector<int> a = {1, 2, 3, 4, 5};
const std::vector<double> b = {1.2, 4.5, 0.6};
const std::vector<std::string> c = {"hi", "howdy", "hello", "bye"};
std::vector<double> result(5);
transform<Foo> (result.begin(),
a.begin(), a.end(),
b.begin(), b.end(),
c.begin(), c.end());
is to carry out a generalization of std::transform on multiple containers, outputing the results in the vector result. One function with signature (int, double, const std::string&) would apparently be needed to handle the three containers in this example. But because the containers have different lengths, we instead need to use some overloads. I will test this using these member overloads of a holder class Foo:
static int execute (int i, double d, const std::string& s) {return i + d + s.length();}
static int execute (int i, const std::string& s) {return 2 * i + s.length();}
static int execute (int i) {return 3 * i - 1;}
However, the program will not compile unless I define three other overloads that are never even called, namely with arguments (int, double), (const std::string&) and (). I want to remove these overloads, but the program won't let me. You can imagine the problem this would cause if we had more than 3 containers (of different lengths), forcing overloads with many permutations of arguments to be defined when they are not even being used.
Here is my working program that will apparently show why these extraneous overloads are needed. I don't see how or why the are forced to be defined, and want to remove them. Why must they be there, and how to remove the need for them?
#include <iostream>
#include <utility>
#include <tuple>
bool allTrue (bool a) {return a;}
template <typename... B>
bool allTrue (bool a, B... b) {return a && allTrue(b...);}
template <typename F, size_t... Js, typename Tuple>
typename F::return_type screenArguments (std::index_sequence<>, std::index_sequence<Js...>, Tuple& tuple) {
return F::execute (*std::get<Js>(tuple)++...);
}
// Thanks to Barry for coming up with screenArguments.
template <typename F, std::size_t I, size_t... Is, size_t... Js, typename Tuple>
typename F::return_type screenArguments (std::index_sequence<I, Is...>, std::index_sequence<Js...>, Tuple& tuple) {
if (std::get<2*I>(tuple) != std::get<2*I+1>(tuple))
return screenArguments<F> (std::index_sequence<Is...>{}, std::index_sequence<Js..., 2*I>{}, tuple);
else
return screenArguments<F> (std::index_sequence<Is...>{}, std::index_sequence<Js...>{}, tuple);
}
template <typename F, typename Tuple>
typename F::return_type passCertainArguments (Tuple& tuple) {
return screenArguments<F> (std::make_index_sequence<std::tuple_size<Tuple>::value / 2>{},
std::index_sequence<>{}, tuple);
}
template <typename F, typename OutputIterator, std::size_t... Is, typename... InputIterators>
OutputIterator transformHelper (OutputIterator result, const std::index_sequence<Is...>&, InputIterators... iterators) {
auto tuple = std::make_tuple(iterators...);
while (!allTrue(std::get<2*Is>(tuple) == std::get<2*Is + 1>(tuple)...))
*result++ = passCertainArguments<F>(tuple);
return result;
}
template <typename F, typename OutputIterator, typename... InputIterators>
OutputIterator transform (OutputIterator result, InputIterators... iterators) {
return transformHelper<F> (result, std::make_index_sequence<sizeof...(InputIterators) / 2>{}, iterators...);
}
// Testing
#include <vector>
struct Foo {
using return_type = int;
static int execute (int i, double d, const std::string& s) {return i + d + s.length();}
static int execute (int i, const std::string& s) {return 2 * i + s.length();}
static int execute (int i) {return 3 * i - 1;}
// These overloads are never called, but apparently must still be defined.
static int execute () {std::cout << "Oveload4 called.\n"; return 0;}
static int execute (int i, double d) {std::cout << "Oveload5 called.\n"; return i + d;}
static int execute (const std::string& s) {std::cout << "Oveload6 called.\n"; return s.length();}
};
int main() {
const std::vector<int> a = {1, 2, 3, 4, 5};
const std::vector<double> b = {1.2, 4.5, 0.6};
const std::vector<std::string> c = {"hi", "howdy", "hello", "bye"};
std::vector<double> result(5);
transform<Foo> (result.begin(),
a.begin(), a.end(),
b.begin(), b.end(),
c.begin(), c.end());
for (double x : result) std::cout << x << ' '; std::cout << '\n';
// 4 11 8 11 14 (correct output)
}
The compiler does not know at compile time which combinations of functions will be used in runtime. So you have to implement all the 2^N functions for every combination. Also your approach will not work when you have containers with the same types.
If you want to stick with templates, my idea is to implement the function something like this:
template <bool Arg1, bool Arg2, bool Arg3>
static int execute (int *i, double *d, const std::string *s);
The template arguments Arg1, Arg2, Arg3 represent the validity of each parameter. The compiler will automatically generate all the 2^N implementations for every parameter combination. Feel free to use if statements inside this function instead of template specialization - they will be resolved at compile time to if (true) or if (false).
I think I got! Template the function Foo::execute according to the number of arguments that are actually needed, and let them all have the same arguments:
struct Foo {
using return_type = int;
template <std::size_t> static return_type execute (int, double, const std::string&);
};
template <> Foo::return_type Foo::execute<3> (int i, double d, const std::string& s) {return i + d + s.length();}
template <> Foo::return_type Foo::execute<2> (int i, double, const std::string& s) {return 2 * i + s.length();}
template <> Foo::return_type Foo::execute<1> (int i, double, const std::string&) {return 3 * i - 1;}
template <> Foo::return_type Foo::execute<0> (int, double, const std::string&) {return 0;} // The only redundant specialization that needs to be defined.
Here is the full solution.
#include <iostream>
#include <utility>
#include <tuple>
#include <iterator>
bool allTrue (bool b) {return b;}
template <typename... Bs>
bool allTrue (bool b, Bs... bs) {return b && allTrue(bs...);}
template <typename F, std::size_t N, typename Tuple, typename... Args>
typename F::return_type countArgumentsNeededAndExecute (Tuple&, const std::index_sequence<>&, Args&&... args) {
return F::template execute<N>(std::forward<Args>(args)...);
}
template <typename F, std::size_t N, typename Tuple, std::size_t I, size_t... Is, typename... Args>
typename F::return_type countArgumentsNeededAndExecute (Tuple& tuple, const std::index_sequence<I, Is...>&, Args&&... args) { // Pass tuple by reference, because its iterator elements will be modified (by being incremented).
return (std::get<2*I>(tuple) != std::get<2*I + 1>(tuple)) ?
countArgumentsNeededAndExecute<F, N+1> (tuple, std::index_sequence<Is...>{}, std::forward<Args>(args)..., // The number of arguments to be used increases by 1.
*std::get<2*I>(tuple)++) : // Pass the value that will be used and increment the iterator.
countArgumentsNeededAndExecute<F, N> (tuple, std::index_sequence<Is...>{}, std::forward<Args>(args)...,
typename std::iterator_traits<typename std::tuple_element<2*I, Tuple>::type>::value_type{}); // Pass the default value (it will be ignored anyway), and don't increment the iterator. Hence, the number of arguments to be used does not change.
}
template <typename F, typename OutputIterator, std::size_t... Is, typename... InputIterators>
OutputIterator transformHelper (OutputIterator result, const std::index_sequence<Is...>& indices, InputIterators... iterators) {
auto tuple = std::make_tuple(iterators...); // Cannot be const, as the iterators are being incremented.
while (!allTrue(std::get<2*Is>(tuple) == std::get<2*Is + 1>(tuple)...))
*result++ = countArgumentsNeededAndExecute<F, 0> (tuple, indices); // Start the count at 0. Examine 'indices', causing the count to increase one by one.
return result;
}
template <typename F, typename OutputIterator, typename... InputIterators>
OutputIterator transform (OutputIterator result, InputIterators... iterators) {
return transformHelper<F> (result, std::make_index_sequence<sizeof...(InputIterators) / 2>{}, iterators...);
}
// Testing
#include <vector>
struct Foo {
using return_type = int;
template <std::size_t> static return_type execute (int, double, const std::string&);
};
// Template the function Foo::execute according to the number of arguments that are actually needed:
template <> Foo::return_type Foo::execute<3> (int i, double d, const std::string& s) {return i + d + s.length();}
template <> Foo::return_type Foo::execute<2> (int i, double, const std::string& s) {return 2 * i + s.length();}
template <> Foo::return_type Foo::execute<1> (int i, double, const std::string&) {return 3 * i - 1;}
template <> Foo::return_type Foo::execute<0> (int, double, const std::string&) {return 0;} // The only redundant specialization that needs to be defined.
int main() {
const std::vector<int> a = {1, 2, 3, 4, 5};
const std::vector<double> b = {1.2, 4.5, 0.6};
const std::vector<std::string> c = {"hi", "howdy", "hello", "bye"};
std::vector<double> result(5);
transform<Foo> (result.begin(),
a.begin(), a.end(),
b.begin(), b.end(),
c.begin(), c.end());
for (double x : result) std::cout << x << ' '; std::cout << '\n';
// 4 11 8 11 14 (correct output)
}
And a second solution using Andrey Nasonov's bool templates to generate all 2^N overloads needed. Note that the above solution requires only N+1 template instantations for the overloads though.
#include <iostream>
#include <utility>
#include <tuple>
bool allTrue (bool b) {return b;}
template <typename... Bs>
bool allTrue (bool b, Bs... bs) {return b && allTrue(bs...);}
template <bool...> struct BoolPack {};
template <typename F, typename Tuple, bool... Bs, typename... Args>
typename F::return_type checkArgumentsAndExecute (const Tuple&, const std::index_sequence<>&, BoolPack<Bs...>, Args&&... args) {
return F::template execute<Bs...>(std::forward<Args>(args)...);
}
template <typename F, typename Tuple, std::size_t I, size_t... Is, bool... Bs, typename... Args>
typename F::return_type checkArgumentsAndExecute (Tuple& tuple, const std::index_sequence<I, Is...>&, BoolPack<Bs...>, Args&&... args) { // Pass tuple by reference, because its iterators elements will be modified (by being incremented).
return (std::get<2*I>(tuple) != std::get<2*I+1>(tuple)) ?
checkArgumentsAndExecute<F> (tuple, std::index_sequence<Is...>{}, BoolPack<Bs..., true>{}, std::forward<Args>(args)...,
*std::get<2*I>(tuple)++) : // Pass the value that will be used and increment the iterator.
checkArgumentsAndExecute<F> (tuple, std::index_sequence<Is...>{}, BoolPack<Bs..., false>{}, std::forward<Args>(args)...,
typename std::iterator_traits<typename std::tuple_element<2*I, Tuple>::type>::value_type{}); // Pass the default value (it will be ignored anyway), and don't increment the iterator.
}
template <typename F, typename OutputIterator, std::size_t... Is, typename... InputIterators>
OutputIterator transformHelper (OutputIterator& result, const std::index_sequence<Is...>& indices, InputIterators... iterators) {
auto tuple = std::make_tuple(iterators...); // Cannot be const, as the iterators are being incremented.
while (!allTrue(std::get<2*Is>(tuple) == std::get<2*Is + 1>(tuple)...))
*result++ = checkArgumentsAndExecute<F> (tuple, indices, BoolPack<>{});
return result;
}
template <typename F, typename OutputIterator, typename... InputIterators>
OutputIterator transform (OutputIterator result, InputIterators... iterators) {
return transformHelper<F> (result, std::make_index_sequence<sizeof...(InputIterators) / 2>{}, iterators...);
}
// Testing
#include <vector>
struct Foo {
using return_type = int;
template <bool B1, bool B2, bool B3> static return_type execute (int, double, const std::string&) {return 0;} // All necessary overloads defined at once here.
};
// Specializations of Foo::execute<B1,B2,B3>(int, double, const std::string&) that will actually be called by transform<Foo> (it is the client's responsibility to define these overloads based on the containers passed to transform<Foo>).
template <> Foo::return_type Foo::execute<true, true, true> (int i, double d, const std::string& s) {return i + d + s.length();}
template <> Foo::return_type Foo::execute<true, false, true> (int i, double, const std::string& s) {return 2 * i + s.length();}
template <> Foo::return_type Foo::execute<true, false, false> (int i, double, const std::string&) {return 3 * i - 1;}
int main() {
const std::vector<int> a = {1, 2, 3, 4, 5};
const std::vector<double> b = {1.2, 4.5, 0.6};
const std::vector<std::string> c = {"hi", "howdy", "hello", "bye"};
std::vector<double> result(5);
transform<Foo> (result.begin(),
a.begin(), a.end(),
b.begin(), b.end(),
c.begin(), c.end());
for (double x : result) std::cout << x << ' '; std::cout << '\n';
// 4 11 8 11 14 (correct output)
}

How do I bind a ::std::vector of arguments to a functor?

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