#include <tuple>
#include <functional>
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <list>
#include <array>
#include <iterator>
// for_each_multi
template<typename Tuple, typename Callable>
Callable for_each_multi(Tuple begins, Tuple ends, Callable fn);
// visit_tuple
template<typename Callable, typename Head, typename... Tail>
Callable visit_tuple(Callable fn, Head&& aTuple, Tail&& ...aTail);
template<size_t size>
struct visit_tuple_ws;
// apply_tuple
template<typename Applicator, typename Tuple, typename Callable>
void apply_tuple(Tuple&& tuple, Callable&& fn);
// tuple unpack utils
template<size_t ...>
struct sequence { };
template<size_t N, size_t ...S>
struct generate : generate<N-1u, N-1u, S...> { };
template<size_t ...S>
struct generate<0u, S...> {
typedef sequence<S...> type;
};
struct Dereference
{
template< typename F, typename T, size_t ...S >
static void apply(T&& tuple, F& fn, sequence<S...> )
{
fn( *std::get<S>(tuple) ...);
}
};
struct Increment
{
template <typename T>
void operator()(T&& t)
{
++t;
}
};
struct CheckBeginEnd
{
CheckBeginEnd() : BeginIsNotEnd(true) {}
template<typename T>
void operator()(T&& begin, T&& end)
{
BeginIsNotEnd &= (begin != end);
}
bool BeginIsNotEnd;
};
// for_each_multi
template<typename Tuple, typename Callable>
Callable for_each_multi(Tuple begins, Tuple ends, Callable fn)
{
for ( ; visit_tuple(CheckBeginEnd(), begins, ends).BeginIsNotEnd; visit_tuple(Increment(), begins) )
apply_tuple<Dereference>(begins, fn);
return fn;
}
template<typename Callable, typename Head, typename... Tail>
Callable for_each_multi(Callable fn, Head&& head, Tail&& ...tail)
{
return for_each_multi( std::make_tuple(begin(head), begin(tail)...), std::make_tuple(end(head), end(tail)...), fn);
}
// visit_tuple
template<typename Callable, typename Head, typename... Tail>
Callable visit_tuple(Callable f, Head&& aTuple, Tail&& ...aTail)
{
const size_t size = std::tuple_size<typename std::remove_reference<Head>::type>::value-1;
visit_tuple_ws<size>::visit(f, aTuple, aTail...);
return f;
}
template<size_t size>
struct visit_tuple_ws
{
template<typename Callable, typename Head, typename... Tail>
static void visit(Callable& f, Head& aTuple, Tail& ...aTail)
{
visit_tuple_ws<size-1>::visit(f, aTuple, aTail...);
f(std::get<size>(aTuple), std::get<size>(aTail)...);
}
};
template<>
struct visit_tuple_ws<0u>
{
template<typename Callable, typename Head, typename... Tail>
static void visit(Callable& f, Head& aTuple, Tail& ...aTail)
{
f(std::get<0>(aTuple), std::get<0>(aTail)...);
}
};
// apply_tuple
template<typename Unpacker, typename Tuple, typename Callable>
void apply_tuple(Tuple&& tuple, Callable&& fn)
{
const int size = std::tuple_size<typename std::remove_reference<Tuple>::type>::value;
Unpacker::apply( std::forward<Tuple>(tuple), std::forward<Callable>(fn), typename generate<size>::type() );
}
using namespace std;
// support
template<typename Head, typename ...Tail>
auto begins(Head&& head, Tail&& ...tail)
-> decltype(std::make_tuple(head.begin(), tail.begin()...))
{
return std::make_tuple(head.begin(), tail.begin()...);
}
template<typename Head, typename ...Tail>
auto ends(Head&& head, Tail&& ...tail)
-> decltype(std::make_tuple(head.end(), tail.end()...))
{
return std::make_tuple(head.end(), tail.end()...);
}
#define ON(...) begins(__VA_ARGS__), ends(__VA_ARGS__)
int main()
{
vector<int> vec1 {1,2,3};
list<int> list1 {10, 20 ,30};
array<string, 3> arr {"one", "two", "three"};
for_each_multi(ON(vec1, list1, arr), [](int i, int l, const string& s)
{
cout << i << " (" << s << ")" << " * 10 is " << l << endl;
});
return 0;
}
I2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8ZnVuY3Rpb25hbD4KI2luY2x1ZGUgPGlvc3RyZWFtPgojaW5jbHVkZSA8c3RyaW5nPgojaW5jbHVkZSA8dmVjdG9yPgojaW5jbHVkZSA8bWFwPgojaW5jbHVkZSA8bGlzdD4KI2luY2x1ZGUgPGFycmF5PgojaW5jbHVkZSA8aXRlcmF0b3I+CgovLyBmb3JfZWFjaF9tdWx0aQp0ZW1wbGF0ZTx0eXBlbmFtZSBUdXBsZSwgdHlwZW5hbWUgQ2FsbGFibGU+CkNhbGxhYmxlIGZvcl9lYWNoX211bHRpKFR1cGxlIGJlZ2lucywgVHVwbGUgZW5kcywgQ2FsbGFibGUgZm4pOwoKLy8gdmlzaXRfdHVwbGUKdGVtcGxhdGU8dHlwZW5hbWUgQ2FsbGFibGUsIHR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lLi4uIFRhaWw+CkNhbGxhYmxlIHZpc2l0X3R1cGxlKENhbGxhYmxlIGZuLCBIZWFkJiYgYVR1cGxlLCBUYWlsJiYgLi4uYVRhaWwpOwoKdGVtcGxhdGU8c2l6ZV90IHNpemU+CnN0cnVjdCB2aXNpdF90dXBsZV93czsKCi8vIGFwcGx5X3R1cGxlCnRlbXBsYXRlPHR5cGVuYW1lIEFwcGxpY2F0b3IsIHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBDYWxsYWJsZT4Kdm9pZCBhcHBseV90dXBsZShUdXBsZSYmIHR1cGxlLCBDYWxsYWJsZSYmIGZuKTsKCi8vIHR1cGxlIHVucGFjayB1dGlscwp0ZW1wbGF0ZTxzaXplX3QgLi4uPgpzdHJ1Y3Qgc2VxdWVuY2UgeyB9OwoKdGVtcGxhdGU8c2l6ZV90IE4sIHNpemVfdCAuLi5TPgpzdHJ1Y3QgZ2VuZXJhdGUgOiBnZW5lcmF0ZTxOLTF1LCBOLTF1LCBTLi4uPiB7IH07Cgp0ZW1wbGF0ZTxzaXplX3QgLi4uUz4Kc3RydWN0IGdlbmVyYXRlPDB1LCBTLi4uPiB7CiAgdHlwZWRlZiBzZXF1ZW5jZTxTLi4uPiB0eXBlOwp9OwoKc3RydWN0IERlcmVmZXJlbmNlIAp7CiAgICB0ZW1wbGF0ZTwgdHlwZW5hbWUgRiwgdHlwZW5hbWUgVCwgc2l6ZV90IC4uLlMgPgoJc3RhdGljIHZvaWQgYXBwbHkoVCYmIHR1cGxlLCBGJiBmbiwgc2VxdWVuY2U8Uy4uLj4gKQoJewoJICAgIGZuKCAqc3RkOjpnZXQ8Uz4odHVwbGUpIC4uLik7Cgl9Cn07CQoKc3RydWN0IEluY3JlbWVudCAKewoJdGVtcGxhdGUgPHR5cGVuYW1lIFQ+Cgl2b2lkIG9wZXJhdG9yKCkoVCYmIHQpIAoJewoJCSsrdDsKCX0KfTsKCnN0cnVjdCBDaGVja0JlZ2luRW5kCnsKCUNoZWNrQmVnaW5FbmQoKSA6IEJlZ2luSXNOb3RFbmQodHJ1ZSkge30KCQoJdGVtcGxhdGU8dHlwZW5hbWUgVD4KCXZvaWQgb3BlcmF0b3IoKShUJiYgYmVnaW4sIFQmJiBlbmQpCgl7CgkJQmVnaW5Jc05vdEVuZCAmPSAoYmVnaW4gIT0gZW5kKTsKCX0JCQoJCQoJYm9vbCBCZWdpbklzTm90RW5kOwp9OwoKLy8gZm9yX2VhY2hfbXVsdGkKdGVtcGxhdGU8dHlwZW5hbWUgVHVwbGUsIHR5cGVuYW1lIENhbGxhYmxlPgpDYWxsYWJsZSBmb3JfZWFjaF9tdWx0aShUdXBsZSBiZWdpbnMsIFR1cGxlIGVuZHMsIENhbGxhYmxlIGZuKQp7CiAgICAgZm9yICggOyB2aXNpdF90dXBsZShDaGVja0JlZ2luRW5kKCksIGJlZ2lucywgZW5kcykuQmVnaW5Jc05vdEVuZDsgdmlzaXRfdHVwbGUoSW5jcmVtZW50KCksIGJlZ2lucykgKQogICAgICAgICAgYXBwbHlfdHVwbGU8RGVyZWZlcmVuY2U+KGJlZ2lucywgZm4pOwogICAgIHJldHVybiBmbjsKfQoKdGVtcGxhdGU8dHlwZW5hbWUgQ2FsbGFibGUsIHR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lLi4uIFRhaWw+CkNhbGxhYmxlIGZvcl9lYWNoX211bHRpKENhbGxhYmxlIGZuLCBIZWFkJiYgaGVhZCwgVGFpbCYmIC4uLnRhaWwpCnsKCXJldHVybiBmb3JfZWFjaF9tdWx0aSggc3RkOjptYWtlX3R1cGxlKGJlZ2luKGhlYWQpLCBiZWdpbih0YWlsKS4uLiksIHN0ZDo6bWFrZV90dXBsZShlbmQoaGVhZCksIGVuZCh0YWlsKS4uLiksIGZuKTsKfQoKLy8gdmlzaXRfdHVwbGUKdGVtcGxhdGU8dHlwZW5hbWUgQ2FsbGFibGUsIHR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lLi4uIFRhaWw+CkNhbGxhYmxlIHZpc2l0X3R1cGxlKENhbGxhYmxlIGYsIEhlYWQmJiBhVHVwbGUsIFRhaWwmJiAuLi5hVGFpbCkKewoJY29uc3Qgc2l6ZV90IHNpemUgPSBzdGQ6OnR1cGxlX3NpemU8dHlwZW5hbWUgc3RkOjpyZW1vdmVfcmVmZXJlbmNlPEhlYWQ+Ojp0eXBlPjo6dmFsdWUtMTsKICAgIHZpc2l0X3R1cGxlX3dzPHNpemU+Ojp2aXNpdChmLCBhVHVwbGUsIGFUYWlsLi4uKTsKICAgIHJldHVybiBmOwp9Cgp0ZW1wbGF0ZTxzaXplX3Qgc2l6ZT4Kc3RydWN0IHZpc2l0X3R1cGxlX3dzCnsKCXRlbXBsYXRlPHR5cGVuYW1lIENhbGxhYmxlLCB0eXBlbmFtZSBIZWFkLCB0eXBlbmFtZS4uLiBUYWlsPgogICAgc3RhdGljIHZvaWQgdmlzaXQoQ2FsbGFibGUmIGYsIEhlYWQmIGFUdXBsZSwgVGFpbCYgLi4uYVRhaWwpCiAgICB7CiAgICAgICAgdmlzaXRfdHVwbGVfd3M8c2l6ZS0xPjo6dmlzaXQoZiwgYVR1cGxlLCBhVGFpbC4uLik7ICAgIAogICAgICAgIGYoc3RkOjpnZXQ8c2l6ZT4oYVR1cGxlKSwgc3RkOjpnZXQ8c2l6ZT4oYVRhaWwpLi4uKTsKICAgIH0KfTsKCnRlbXBsYXRlPD4Kc3RydWN0IHZpc2l0X3R1cGxlX3dzPDB1Pgp7Cgl0ZW1wbGF0ZTx0eXBlbmFtZSBDYWxsYWJsZSwgdHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUuLi4gVGFpbD4KICAgIHN0YXRpYyB2b2lkIHZpc2l0KENhbGxhYmxlJiBmLCBIZWFkJiBhVHVwbGUsIFRhaWwmIC4uLmFUYWlsKQogICAgewkKICAgICAgICAgZihzdGQ6OmdldDwwPihhVHVwbGUpLCBzdGQ6OmdldDwwPihhVGFpbCkuLi4pOwogICAgfQp9OwoKLy8gYXBwbHlfdHVwbGUKdGVtcGxhdGU8dHlwZW5hbWUgVW5wYWNrZXIsIHR5cGVuYW1lIFR1cGxlLCB0eXBlbmFtZSBDYWxsYWJsZT4Kdm9pZCBhcHBseV90dXBsZShUdXBsZSYmIHR1cGxlLCBDYWxsYWJsZSYmIGZuKQp7Cgljb25zdCBpbnQgc2l6ZSA9IHN0ZDo6dHVwbGVfc2l6ZTx0eXBlbmFtZSBzdGQ6OnJlbW92ZV9yZWZlcmVuY2U8VHVwbGU+Ojp0eXBlPjo6dmFsdWU7CglVbnBhY2tlcjo6YXBwbHkoIHN0ZDo6Zm9yd2FyZDxUdXBsZT4odHVwbGUpLCBzdGQ6OmZvcndhcmQ8Q2FsbGFibGU+KGZuKSwgdHlwZW5hbWUgZ2VuZXJhdGU8c2l6ZT46OnR5cGUoKSApOwp9CgoKdXNpbmcgbmFtZXNwYWNlIHN0ZDsKCi8vIHN1cHBvcnQKdGVtcGxhdGU8dHlwZW5hbWUgSGVhZCwgdHlwZW5hbWUgLi4uVGFpbD4KYXV0byBiZWdpbnMoSGVhZCYmIGhlYWQsIFRhaWwmJiAuLi50YWlsKQogICAgLT4gZGVjbHR5cGUoc3RkOjptYWtlX3R1cGxlKGhlYWQuYmVnaW4oKSwgdGFpbC5iZWdpbigpLi4uKSkKewoJcmV0dXJuIHN0ZDo6bWFrZV90dXBsZShoZWFkLmJlZ2luKCksIHRhaWwuYmVnaW4oKS4uLik7Cn0KCnRlbXBsYXRlPHR5cGVuYW1lIEhlYWQsIHR5cGVuYW1lIC4uLlRhaWw+CmF1dG8gZW5kcyhIZWFkJiYgaGVhZCwgVGFpbCYmIC4uLnRhaWwpCgktPiBkZWNsdHlwZShzdGQ6Om1ha2VfdHVwbGUoaGVhZC5lbmQoKSwgdGFpbC5lbmQoKS4uLikpCnsKCXJldHVybiBzdGQ6Om1ha2VfdHVwbGUoaGVhZC5lbmQoKSwgdGFpbC5lbmQoKS4uLik7Cn0KCiNkZWZpbmUgT04oLi4uKSBiZWdpbnMoX19WQV9BUkdTX18pLCBlbmRzKF9fVkFfQVJHU19fKQoKaW50IG1haW4oKQp7CiAgICB2ZWN0b3I8aW50PiB2ZWMxIHsxLDIsM307CiAgICBsaXN0PGludD4gbGlzdDEgezEwLCAyMCAsMzB9OwoJYXJyYXk8c3RyaW5nLCAzPiBhcnIgeyJvbmUiLCAidHdvIiwgInRocmVlIn07CgkKICAgIGZvcl9lYWNoX211bHRpKE9OKHZlYzEsIGxpc3QxLCBhcnIpLCBbXShpbnQgaSwgaW50IGwsIGNvbnN0IHN0cmluZyYgcykKICAgIHsKICAgICAgICBjb3V0IDw8IGkgPDwgIiAoIiA8PCBzIDw8ICIpIiA8PCAiICogMTAgaXMgIiA8PCBsIDw8IGVuZGw7CiAgICB9KTsKCQogICAgcmV0dXJuIDA7Cn0=