Last active
December 29, 2015 21:49
-
-
Save quartorz/7733015 to your computer and use it in GitHub Desktop.
caller
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <iostream> | |
#include <tuple> | |
#include <string> | |
extern void *enabler; | |
template <class... Functions> | |
class caller{ | |
template <unsigned... I> | |
class sequence{ | |
template <unsigned J> | |
class append_impl{ | |
public: | |
using type = sequence<I..., J>; | |
}; | |
template <unsigned...> | |
class extract{ | |
public: | |
static const unsigned head = -1; | |
using tail = void; | |
}; | |
template <unsigned Head, unsigned... Tail> | |
class extract<Head, Tail...>{ | |
public: | |
static const unsigned head = Head; | |
using tail = sequence<Tail...>; | |
}; | |
public: | |
template <unsigned N> | |
using append = typename append_impl<N>::type; | |
static const unsigned head = extract<I...>::head; | |
using tail = typename extract<I...>::tail; | |
static const unsigned length = sizeof...(I); | |
}; | |
template <unsigned I> | |
class make_sequence_impl{ | |
template <unsigned N, bool = N == 0> | |
class maker{ | |
public: | |
using type = sequence<>; | |
}; | |
template <unsigned N> | |
class maker<N, false>{ | |
public: | |
using type = typename maker<N - 1>::type::template append<N - 1>; | |
}; | |
public: | |
using type = typename maker<I>::type; | |
}; | |
template <unsigned I> | |
using make_sequence = typename make_sequence_impl<I>::type; | |
std::tuple<Functions...> functions; | |
template <class Sequence, typename std::enable_if<Sequence::length != 0>::type*& = enabler, class... Args> | |
void call_impl(Args... args) | |
{ | |
std::get<Sequence::head>(functions)(args...); | |
call_impl<typename Sequence::tail>(args...); | |
} | |
template <class Sequence, typename std::enable_if<Sequence::length == 0>::type*& = enabler, class... Args> | |
void call_impl(Args...) | |
{ | |
} | |
public: | |
caller(Functions... funcs): functions(funcs...) | |
{ | |
} | |
template <class... Args> | |
void operator()(Args... args) | |
{ | |
call_impl<make_sequence<sizeof...(Functions)>>(args...); | |
} | |
}; | |
template <class... Functions> | |
caller<Functions...> make_caller(Functions... funcs) | |
{ | |
return caller<Functions...>(funcs...); | |
} | |
void f(const char *s, int a, int b) | |
{ | |
std::cout << "void f(const char*, int, int): " << s << ' ' << a << ' ' << b << std::endl; | |
} | |
class Class1{ | |
public: | |
void operator()(std::string s, int a, int b) | |
{ | |
std::cout << "Class1::operator(): " << s << ' ' << a << ' ' << b << std::endl; | |
} | |
}; | |
class Class2{ | |
public: | |
template <class Type> | |
void operator()(Type s, int a, int b) | |
{ | |
std::cout << "Class2::operator(): " << s << ' ' << a << ' ' << b << std::endl; | |
} | |
}; | |
int main() | |
{ | |
make_caller()(); | |
auto caller = make_caller([](const char *s, int a, ...){ | |
std::cout << "first lambda function: " << s << ' ' << a << std::endl; | |
}, [](const char *s, int a, int b){ | |
std::cout << "second lambda function: " << s << ' ' << a << ' ' << b << std::endl; | |
}, f, Class1(), Class2()); | |
caller("string1", 0, 1); | |
std::cout << std::endl; | |
caller("string2", 2, 3); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment