#include <cstdio>
#include <tuple>
#include <utility>
#include <type_traits>
template<int ...I> struct index_tuple_type {
template<int N> using append = index_tuple_type<I..., N>;
};
template<int N> struct make_index_impl {
using type = typename make_index_impl<N-1>::type::template append<N-1>;
};
template<> struct make_index_impl<0> { using type = index_tuple_type<>; };
template<int N> using index_tuple = typename make_index_impl<N>::type;
template <typename I, typename ...Args>
struct func_traits;
template <typename R, int ...I, typename ...Args>
struct func_traits<R, index_tuple_type<I...>, Args...> {
template <typename TT, typename FT>
static inline R call(TT &&t, FT &&f) {
return f(std::get<I>(std::forward<TT>(t))...);
}
};
#define _explode_variant(_T) \
template <typename FT, typename ...Args, typename R = typename std::result_of<FT(Args&&...)>::type> \
inline R explode(_T t, FT &&f) { \
return func_traits<R, index_tuple<sizeof...(Args)>, Args...> \
::call(std::forward<_T>(t), std::forward<FT>(f)); \
}
_explode_variant(const std::tuple<Args...>&)
_explode_variant( std::tuple<Args...>&)
_explode_variant( std::tuple<Args...>&&)
#undef _explode_variant
//----------------------------------------------------------------------
void test1(int i, char c) {
printf("%d %c\n", i, c);
}
struct S {
int operator()(int, int) { return 5; }
double operator()(int) { return 3.14; }
};
struct Object {
Object() = default;
Object(const Object&) { printf("copying\n"); }
Object(Object&&) { printf("moving\n"); }
};
void test5(Object a, Object b, Object c) {
printf("in test5, moving\n");
}
void test6(Object a, Object b, Object c) {
printf("in test6, copying\n");
}
int main() {
std::tuple<int, char> t1{57, 'a'};
explode(t1, test1);
S s;
// test correct return value deduction, based on implicit type conversion
std::tuple<float> t2{5};
printf("%f\n", explode(t2, s));
std::tuple<int, int> t3{1, 7};
printf("%d\n", explode(t3, s));
// lambdas
auto t4 = std::make_tuple("value: ", 10);
explode(std::move(t4), [](const char *prompt, int value) { printf("%s%d\n", prompt, value); });
// move!
printf("starting test 5\n");
auto t5 = std::make_tuple(Object{}, Object{}, Object{});
printf("exploding, moving!\n");
explode(std::move(t5), test5);
// copy
printf("starting test 6\n");
auto t6 = std::make_tuple(Object{}, Object{}, Object{});
printf("exploding, copying!\n");
explode(t6, test6);
}
I2luY2x1ZGUgPGNzdGRpbz4KI2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8dXRpbGl0eT4KI2luY2x1ZGUgPHR5cGVfdHJhaXRzPgoKdGVtcGxhdGU8aW50IC4uLkk+IHN0cnVjdCBpbmRleF90dXBsZV90eXBlIHsKCXRlbXBsYXRlPGludCBOPiB1c2luZyBhcHBlbmQgPSBpbmRleF90dXBsZV90eXBlPEkuLi4sIE4+Owp9Owp0ZW1wbGF0ZTxpbnQgTj4gc3RydWN0IG1ha2VfaW5kZXhfaW1wbCB7Cgl1c2luZyB0eXBlID0gdHlwZW5hbWUgbWFrZV9pbmRleF9pbXBsPE4tMT46OnR5cGU6OnRlbXBsYXRlIGFwcGVuZDxOLTE+Owp9Owp0ZW1wbGF0ZTw+IHN0cnVjdCBtYWtlX2luZGV4X2ltcGw8MD4geyB1c2luZyB0eXBlID0gaW5kZXhfdHVwbGVfdHlwZTw+OyB9Owp0ZW1wbGF0ZTxpbnQgTj4gdXNpbmcgaW5kZXhfdHVwbGUgPSB0eXBlbmFtZSBtYWtlX2luZGV4X2ltcGw8Tj46OnR5cGU7Cgp0ZW1wbGF0ZSA8dHlwZW5hbWUgSSwgdHlwZW5hbWUgLi4uQXJncz4Kc3RydWN0IGZ1bmNfdHJhaXRzOwoKdGVtcGxhdGUgPHR5cGVuYW1lIFIsIGludCAuLi5JLCB0eXBlbmFtZSAuLi5BcmdzPgpzdHJ1Y3QgZnVuY190cmFpdHM8UiwgaW5kZXhfdHVwbGVfdHlwZTxJLi4uPiwgQXJncy4uLj4gewoJdGVtcGxhdGUgPHR5cGVuYW1lIFRULCB0eXBlbmFtZSBGVD4KCXN0YXRpYyBpbmxpbmUgUiBjYWxsKFRUICYmdCwgRlQgJiZmKSB7CgkJcmV0dXJuIGYoc3RkOjpnZXQ8ST4oc3RkOjpmb3J3YXJkPFRUPih0KSkuLi4pOwoJfQp9OwoKI2RlZmluZSBfZXhwbG9kZV92YXJpYW50KF9UKQkJCQkJCQkJCQlcCnRlbXBsYXRlIDx0eXBlbmFtZSBGVCwgdHlwZW5hbWUgLi4uQXJncywgdHlwZW5hbWUgUiA9IHR5cGVuYW1lIHN0ZDo6cmVzdWx0X29mPEZUKEFyZ3MmJi4uLik+Ojp0eXBlPglcCmlubGluZSBSIGV4cGxvZGUoX1QgdCwgRlQgJiZmKSB7CQkJCQkJCQkJXAoJcmV0dXJuIGZ1bmNfdHJhaXRzPFIsIGluZGV4X3R1cGxlPHNpemVvZi4uLihBcmdzKT4sIEFyZ3MuLi4+CQkJCQlcCgkJOjpjYWxsKHN0ZDo6Zm9yd2FyZDxfVD4odCksIHN0ZDo6Zm9yd2FyZDxGVD4oZikpOwkJCQkJXAp9CgpfZXhwbG9kZV92YXJpYW50KGNvbnN0IHN0ZDo6dHVwbGU8QXJncy4uLj4mKQpfZXhwbG9kZV92YXJpYW50KCAgICAgIHN0ZDo6dHVwbGU8QXJncy4uLj4mKQpfZXhwbG9kZV92YXJpYW50KCAgICAgIHN0ZDo6dHVwbGU8QXJncy4uLj4mJikKCiN1bmRlZiBfZXhwbG9kZV92YXJpYW50CgovLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0KCnZvaWQgdGVzdDEoaW50IGksIGNoYXIgYykgewoJcHJpbnRmKCIlZCAlY1xuIiwgaSwgYyk7Cn0KCnN0cnVjdCBTIHsKCWludCBvcGVyYXRvcigpKGludCwgaW50KSB7IHJldHVybiA1OyB9Cglkb3VibGUgb3BlcmF0b3IoKShpbnQpIHsgcmV0dXJuIDMuMTQ7IH0KfTsKCnN0cnVjdCBPYmplY3QgewoJT2JqZWN0KCkgPSBkZWZhdWx0OwoJT2JqZWN0KGNvbnN0IE9iamVjdCYpICB7IHByaW50ZigiY29weWluZ1xuIik7IH0KCU9iamVjdChPYmplY3QmJikgeyBwcmludGYoIm1vdmluZ1xuIik7IH0KfTsKCnZvaWQgdGVzdDUoT2JqZWN0IGEsIE9iamVjdCBiLCBPYmplY3QgYykgewoJcHJpbnRmKCJpbiB0ZXN0NSwgbW92aW5nXG4iKTsKfQoKdm9pZCB0ZXN0NihPYmplY3QgYSwgT2JqZWN0IGIsIE9iamVjdCBjKSB7CglwcmludGYoImluIHRlc3Q2LCBjb3B5aW5nXG4iKTsKfQoKaW50IG1haW4oKSB7CglzdGQ6OnR1cGxlPGludCwgY2hhcj4gdDF7NTcsICdhJ307CglleHBsb2RlKHQxLCB0ZXN0MSk7CgoJUyBzOwoJLy8gdGVzdCBjb3JyZWN0IHJldHVybiB2YWx1ZSBkZWR1Y3Rpb24sIGJhc2VkIG9uIGltcGxpY2l0IHR5cGUgY29udmVyc2lvbgoJc3RkOjp0dXBsZTxmbG9hdD4gdDJ7NX07CglwcmludGYoIiVmXG4iLCBleHBsb2RlKHQyLCBzKSk7CgoJc3RkOjp0dXBsZTxpbnQsIGludD4gdDN7MSwgN307CglwcmludGYoIiVkXG4iLCBleHBsb2RlKHQzLCBzKSk7CgoJLy8gbGFtYmRhcwoJYXV0byB0NCA9IHN0ZDo6bWFrZV90dXBsZSgidmFsdWU6ICIsIDEwKTsKCWV4cGxvZGUoc3RkOjptb3ZlKHQ0KSwgW10oY29uc3QgY2hhciAqcHJvbXB0LCBpbnQgdmFsdWUpIHsgcHJpbnRmKCIlcyVkXG4iLCBwcm9tcHQsIHZhbHVlKTsgfSk7CgoJLy8gbW92ZSEKCXByaW50Zigic3RhcnRpbmcgdGVzdCA1XG4iKTsKCWF1dG8gdDUgPSBzdGQ6Om1ha2VfdHVwbGUoT2JqZWN0e30sIE9iamVjdHt9LCBPYmplY3R7fSk7CglwcmludGYoImV4cGxvZGluZywgbW92aW5nIVxuIik7CglleHBsb2RlKHN0ZDo6bW92ZSh0NSksIHRlc3Q1KTsKCgkvLyBjb3B5CglwcmludGYoInN0YXJ0aW5nIHRlc3QgNlxuIik7CglhdXRvIHQ2ID0gc3RkOjptYWtlX3R1cGxlKE9iamVjdHt9LCBPYmplY3R7fSwgT2JqZWN0e30pOwoJcHJpbnRmKCJleHBsb2RpbmcsIGNvcHlpbmchXG4iKTsKCWV4cGxvZGUodDYsIHRlc3Q2KTsKfQoKCg==