I want a generic zipWith function in C++ of variable arity. I have two problems. The first is that I cannot determine the type of the function pointer passed to zipWith. It must
Here is what I cobbled together:
#include
#include
#include
template
auto fold(F f, T&& t, Arg&& a)
-> decltype(f(std::forward(t), std::forward(a)))
{ return f(std::forward(t), std::forward(a)); }
template
auto fold(F f, T&& init, Head&& h, Args&&... args)
-> decltype(f(std::forward(init), std::forward(h)))
{
return fold(f, f(std::forward(init), std::forward(h)),
std::forward(args)...);
}
// hack in a fold for void functions
struct ignore {};
// cannot be a lambda, needs to be polymorphic on the iterator type
struct end_or {
template
bool operator()(bool in, const std::pair& p)
{ return in || p.first == p.second; }
};
// same same but different
struct inc {
template
ignore operator()(ignore, std::pair& p)
{ p.first++; return ignore(); }
};
template
void zipWith(Fun f, OutputIterator out,
std::pair... inputs) {
if(fold(end_or(), false, inputs...)) return;
while(!fold(end_or(), false, inputs...)) {
*out++ = f( *(inputs.first)... );
fold(inc(), ignore(), inputs...);
}
}
template
void transformV(Fun f, OutputIterator out, InputIterator begin, InputIterator end,
Rest... rest)
{
if(begin == end) return ;
while(begin != end) {
*out++ = f(*begin, *(rest)... );
fold(inc2(), ignore(), begin, rest...);
}
}
struct ternary_plus {
template
auto operator()(const T& t, const U& u, const V& v)
-> decltype( t + u + v) // common type?
{ return t + u + v; }
};
int main()
{
using namespace std;
vector a = {1, 2, 3}, b = {1, 2}, c = {1, 2, 3};
vector out;
zipWith(ternary_plus(), back_inserter(out)
, make_pair(begin(a), end(a))
, make_pair(begin(b), end(b))
, make_pair(begin(c), end(c)));
transformV(ternary_plus(), back_inserter(out),
begin(a), end(a), begin(b), begin(c));
for(auto x : out) {
std::cout << x << std::endl;
}
return 0;
}
This is a slightly improved variant over previous versions. As every good program should, it starts by defining a left-fold.
It still does not solve the problem of iterators packed in pairs.
In stdlib terms this function would be called transform
and would
require that only the length of one sequence is specified and the
others be at least as long. I called it transformV
here to avoid
name clashes.