#include <tuple>
#include <experimental/tuple>
#include <type_traits>
#include <iostream>
#include <typeinfo>
template<bool Condition,
typename Then,
typename Else>
using if_t = typename std::conditional<
Condition, Then, Else>::type;
struct Ignore {
template<typename Tuple>
static std::tuple<> from(Tuple) {
return {};
}
};
template<std::size_t N>
struct Use {
template<typename Tuple>
static auto from(Tuple t) {
return std:: make_tuple(std::get<N>(t));
}
};
template<
std::size_t N,
typename... Args,
std::size_t... Is>
auto tuple_remove_impl(
std::tuple<Args...> const & t,
std::index_sequence<Is...>) {
return std::tuple_cat(if_t<N == Is, Ignore, Use<Is>>::from(t)...);
}
template<
std::size_t N,
typename... Args>
auto tuple_remove (std::tuple<Args...> const & t) {
return tuple_remove_impl<N>(t, std::index_sequence_for<Args...>{});
}
template<
std::size_t N,
typename Extractor,
typename R,
typename... Args>
R trampoline (Args... args) {
auto all = std::make_tuple(std::ref(args)...);
auto arguments = tuple_remove<N>(all);
return std::experimental::apply(
Extractor{}.get_function(std::get<N>(all)),
arguments);
}
template<std::size_t Num>
struct Multi {
template<std::size_t I, typename R, typename... Args>
struct Extract {
std::function<R(Args...)> & get_function(void * ptr) {
auto arr = static_cast<std::array<void *, Num> *>(ptr);
return *(static_cast<std::function<R(Args...)>*>((*arr)[I]));
}
};
template<typename... Fns>
static void * wrap(Fns &... fns) {
static_assert(sizeof...(fns) == Num, "Don't lie!");
std::array<void *, Num> arr = { static_cast<void *>(&fns)... };
return static_cast<void*>(new std::array<void *, Num>(std::move(arr)));
}
static void free_wrap_result(void * ptr) {
delete (static_cast<std::array<void *, Num>*>(ptr));
}
};
struct Single {
template<typename R, typename... Args>
struct Extract {
std::function<R(Args...)> & get_function(void * ptr) {
return *(static_cast<std::function<R(Args...)>*>(ptr));
}
};
template<typename R, typename... Args>
static void * wrap(std::function<R(Args...)> & fn) {
return &fn;
}
};
void call_one(void (*fn)(int, void *), void * data) {
fn(21, data);
}
void call_two(void (*fn)(char const *, void *, double), void * data) {
fn("FOO", data, 3.14);
}
void call_both(void (*fn)(int, void *), void (*gn)(char const *, void*, double), void * data) {
call_one(fn, data);
call_two(gn, data);
}
int main() {
int offset = 21;
std::function<void(int)> fn = [&offset] (int value) {
std::cout << "FN: " << (offset + value) << std::endl; };
std::function<void(char const *, double)> gn = [] (char const * msg, double value) {
std::cout << "GN: " << msg << " - " << value << std::endl; };
std::cout << "Single test:" << std::endl;
call_one(trampoline<1, Single::Extract<void,int>, void, int, void *>, Single::wrap(fn));
std::cout << "Multi test:" << std::endl;
offset = 0;
auto fns = Multi<2>::wrap(fn, gn);
call_both(trampoline<1, Multi<2>::Extract<0, void, int>, void, int, void *>,
trampoline<1, Multi<2>::Extract<1, void, char const *, double>, void, char const *, void *, double>,
fns);
Multi<2>::free_wrap_result(fns);
}
I2luY2x1ZGUgPHR1cGxlPgojaW5jbHVkZSA8ZXhwZXJpbWVudGFsL3R1cGxlPgojaW5jbHVkZSA8dHlwZV90cmFpdHM+CgojaW5jbHVkZSA8aW9zdHJlYW0+CiNpbmNsdWRlIDx0eXBlaW5mbz4KCnRlbXBsYXRlPGJvb2wgQ29uZGl0aW9uLAogICAgICAgICB0eXBlbmFtZSBUaGVuLAogICAgICAgICB0eXBlbmFtZSBFbHNlPgp1c2luZyBpZl90ID0gdHlwZW5hbWUgc3RkOjpjb25kaXRpb25hbDwKICAgIENvbmRpdGlvbiwgVGhlbiwgRWxzZT46OnR5cGU7CgoKc3RydWN0IElnbm9yZSB7CiAgdGVtcGxhdGU8dHlwZW5hbWUgVHVwbGU+CiAgc3RhdGljIHN0ZDo6dHVwbGU8PiBmcm9tKFR1cGxlKSB7CiAgICByZXR1cm4ge307CiAgfQp9Owp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOPgpzdHJ1Y3QgVXNlIHsKICB0ZW1wbGF0ZTx0eXBlbmFtZSBUdXBsZT4KICBzdGF0aWMgYXV0byBmcm9tKFR1cGxlIHQpIHsKICAgIHJldHVybiBzdGQ6OiBtYWtlX3R1cGxlKHN0ZDo6Z2V0PE4+KHQpKTsKICB9Cn07CgoKdGVtcGxhdGU8CiAgICBzdGQ6OnNpemVfdCBOLAogICAgdHlwZW5hbWUuLi4gQXJncywKICAgIHN0ZDo6c2l6ZV90Li4uIElzPgphdXRvIHR1cGxlX3JlbW92ZV9pbXBsKAogICAgc3RkOjp0dXBsZTxBcmdzLi4uPiBjb25zdCAmIHQsCiAgICBzdGQ6OmluZGV4X3NlcXVlbmNlPElzLi4uPikgewogIHJldHVybiBzdGQ6OnR1cGxlX2NhdChpZl90PE4gPT0gSXMsIElnbm9yZSwgVXNlPElzPj46OmZyb20odCkuLi4pOwp9CnRlbXBsYXRlPAogICAgc3RkOjpzaXplX3QgTiwKICAgIHR5cGVuYW1lLi4uIEFyZ3M+CmF1dG8gdHVwbGVfcmVtb3ZlIChzdGQ6OnR1cGxlPEFyZ3MuLi4+IGNvbnN0ICYgdCkgewogIHJldHVybiB0dXBsZV9yZW1vdmVfaW1wbDxOPih0LCBzdGQ6OmluZGV4X3NlcXVlbmNlX2ZvcjxBcmdzLi4uPnt9KTsKfQoKCnRlbXBsYXRlPAogICAgc3RkOjpzaXplX3QgTiwKICAgIHR5cGVuYW1lIEV4dHJhY3RvciwKICAgIHR5cGVuYW1lIFIsCiAgICB0eXBlbmFtZS4uLiBBcmdzPgpSIHRyYW1wb2xpbmUgKEFyZ3MuLi4gYXJncykgewogIGF1dG8gYWxsID0gc3RkOjptYWtlX3R1cGxlKHN0ZDo6cmVmKGFyZ3MpLi4uKTsKICBhdXRvIGFyZ3VtZW50cyA9IHR1cGxlX3JlbW92ZTxOPihhbGwpOwogIHJldHVybiBzdGQ6OmV4cGVyaW1lbnRhbDo6YXBwbHkoCiAgICBFeHRyYWN0b3J7fS5nZXRfZnVuY3Rpb24oc3RkOjpnZXQ8Tj4oYWxsKSksCiAgICBhcmd1bWVudHMpOwp9Cgp0ZW1wbGF0ZTxzdGQ6OnNpemVfdCBOdW0+CnN0cnVjdCBNdWx0aSB7CiAgdGVtcGxhdGU8c3RkOjpzaXplX3QgSSwgdHlwZW5hbWUgUiwgdHlwZW5hbWUuLi4gQXJncz4KICBzdHJ1Y3QgRXh0cmFjdCB7CiAgICBzdGQ6OmZ1bmN0aW9uPFIoQXJncy4uLik+ICYgZ2V0X2Z1bmN0aW9uKHZvaWQgKiBwdHIpIHsKICAgICAgYXV0byBhcnIgPSBzdGF0aWNfY2FzdDxzdGQ6OmFycmF5PHZvaWQgKiwgTnVtPiAqPihwdHIpOwogICAgICByZXR1cm4gKihzdGF0aWNfY2FzdDxzdGQ6OmZ1bmN0aW9uPFIoQXJncy4uLik+Kj4oKCphcnIpW0ldKSk7CiAgICB9CiAgfTsKICB0ZW1wbGF0ZTx0eXBlbmFtZS4uLiBGbnM+CiAgc3RhdGljIHZvaWQgKiB3cmFwKEZucyAmLi4uIGZucykgewogIAlzdGF0aWNfYXNzZXJ0KHNpemVvZi4uLihmbnMpID09IE51bSwgIkRvbid0IGxpZSEiKTsKICAJc3RkOjphcnJheTx2b2lkICosIE51bT4gYXJyID0geyBzdGF0aWNfY2FzdDx2b2lkICo+KCZmbnMpLi4uIH07CiAgCXJldHVybiBzdGF0aWNfY2FzdDx2b2lkKj4obmV3IHN0ZDo6YXJyYXk8dm9pZCAqLCBOdW0+KHN0ZDo6bW92ZShhcnIpKSk7CiAgfQogIHN0YXRpYyB2b2lkIGZyZWVfd3JhcF9yZXN1bHQodm9pZCAqIHB0cikgewogIAlkZWxldGUgKHN0YXRpY19jYXN0PHN0ZDo6YXJyYXk8dm9pZCAqLCBOdW0+Kj4ocHRyKSk7CiAgfQp9OwoKc3RydWN0IFNpbmdsZSB7CiAgdGVtcGxhdGU8dHlwZW5hbWUgUiwgdHlwZW5hbWUuLi4gQXJncz4KICBzdHJ1Y3QgRXh0cmFjdCB7CiAgCXN0ZDo6ZnVuY3Rpb248UihBcmdzLi4uKT4gJiBnZXRfZnVuY3Rpb24odm9pZCAqIHB0cikgewogIAkJcmV0dXJuICooc3RhdGljX2Nhc3Q8c3RkOjpmdW5jdGlvbjxSKEFyZ3MuLi4pPio+KHB0cikpOwogIAl9CiAgfTsKICAKICB0ZW1wbGF0ZTx0eXBlbmFtZSBSLCB0eXBlbmFtZS4uLiBBcmdzPgogIHN0YXRpYyB2b2lkICogd3JhcChzdGQ6OmZ1bmN0aW9uPFIoQXJncy4uLik+ICYgZm4pIHsKICAJcmV0dXJuICZmbjsKICB9Cn07Cgp2b2lkIGNhbGxfb25lKHZvaWQgKCpmbikoaW50LCB2b2lkICopLCB2b2lkICogZGF0YSkgewogIGZuKDIxLCBkYXRhKTsKfQoKdm9pZCBjYWxsX3R3byh2b2lkICgqZm4pKGNoYXIgY29uc3QgKiwgdm9pZCAqLCBkb3VibGUpLCB2b2lkICogZGF0YSkgewogIGZuKCJGT08iLCBkYXRhLCAzLjE0KTsKfQoKdm9pZCBjYWxsX2JvdGgodm9pZCAoKmZuKShpbnQsIHZvaWQgKiksIHZvaWQgKCpnbikoY2hhciBjb25zdCAqLCB2b2lkKiwgZG91YmxlKSwgdm9pZCAqIGRhdGEpIHsKICBjYWxsX29uZShmbiwgZGF0YSk7CiAgY2FsbF90d28oZ24sIGRhdGEpOwp9CgppbnQgbWFpbigpIHsKCWludCBvZmZzZXQgPSAyMTsKCXN0ZDo6ZnVuY3Rpb248dm9pZChpbnQpPiBmbiA9IFsmb2Zmc2V0XSAoaW50IHZhbHVlKSB7CgkJc3RkOjpjb3V0IDw8ICJGTjogIiA8PCAob2Zmc2V0ICsgdmFsdWUpIDw8IHN0ZDo6ZW5kbDsgfTsKCXN0ZDo6ZnVuY3Rpb248dm9pZChjaGFyIGNvbnN0ICosIGRvdWJsZSk+IGduID0gW10gKGNoYXIgY29uc3QgKiBtc2csIGRvdWJsZSB2YWx1ZSkgewoJCXN0ZDo6Y291dCA8PCAiR046ICIgPDwgbXNnIDw8ICIgLSAiIDw8IHZhbHVlIDw8IHN0ZDo6ZW5kbDsgfTsKCQoJc3RkOjpjb3V0IDw8ICJTaW5nbGUgdGVzdDoiIDw8IHN0ZDo6ZW5kbDsKCWNhbGxfb25lKHRyYW1wb2xpbmU8MSwgU2luZ2xlOjpFeHRyYWN0PHZvaWQsaW50Piwgdm9pZCwgaW50LCB2b2lkICo+LCBTaW5nbGU6OndyYXAoZm4pKTsKCQoJc3RkOjpjb3V0IDw8ICJNdWx0aSB0ZXN0OiIgPDwgc3RkOjplbmRsOwoJb2Zmc2V0ID0gMDsKCWF1dG8gZm5zID0gTXVsdGk8Mj46OndyYXAoZm4sIGduKTsKCWNhbGxfYm90aCh0cmFtcG9saW5lPDEsIE11bHRpPDI+OjpFeHRyYWN0PDAsIHZvaWQsIGludD4sIHZvaWQsIGludCwgdm9pZCAqPiwKCSAgICAgICAgICB0cmFtcG9saW5lPDEsIE11bHRpPDI+OjpFeHRyYWN0PDEsIHZvaWQsIGNoYXIgY29uc3QgKiwgZG91YmxlPiwgdm9pZCwgY2hhciBjb25zdCAqLCB2b2lkICosIGRvdWJsZT4sCgkgICAgICAgICAgZm5zKTsKCU11bHRpPDI+OjpmcmVlX3dyYXBfcmVzdWx0KGZucyk7Cn0=