Skip to content

Instantly share code, notes, and snippets.

@PkmX
Last active August 29, 2015 14:22
Show Gist options
  • Save PkmX/0fa65c755c39b676d79e to your computer and use it in GitHub Desktop.
Save PkmX/0fa65c755c39b676d79e to your computer and use it in GitHub Desktop.
#include <functional>
#include <iostream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <tuple>
#include <experimental/tuple>
#include <boost/variant.hpp>
namespace std {
using std::experimental::apply;
}
using empty_t = std::tuple<>;
namespace detail {
template<typename T> struct storable_of { using type = T; };
template<> struct storable_of<void> { using type = empty_t; };
template<typename T> using storable_of_t = typename storable_of<T>::type;
template<typename Args, typename... F>
struct index_call_result_type {
using type = boost::variant<storable_of_t<decltype(std::apply(std::forward<F>(std::declval<F>()), std::forward<Args>(std::declval<Args>())))>..., empty_t>;
};
template<typename... T> using index_call_result_type_t = typename index_call_result_type<T...>::type;
template<typename F>
auto make_storable(F&& f) -> std::enable_if_t<std::is_void<decltype(f())>{}, storable_of_t<void>> {
f(); return {};
}
template<typename F>
auto make_storable(F&& f) -> std::enable_if_t<!std::is_void<decltype(f())>{}, storable_of_t<decltype(f())>> {
return f();
}
}
template<typename Args>
auto index_call(const std::size_t, Args&&) -> detail::index_call_result_type_t<Args> {
throw std::out_of_range("index_call: out of range");
}
template<typename Args, typename F, typename... FS>
auto index_call(const std::size_t i, Args&& args, F&& f, FS&&... fs) -> detail::index_call_result_type_t<Args, F, FS...> {
if (i == 0) {
return detail::make_storable([&] { return std::apply(std::forward<F>(f), std::forward<Args>(args)); });
} else {
return index_call(i - 1, std::forward<Args>(args), std::forward<FS>(fs)...);
}
}
void f1(const int x) { std::cout << "f1: " << x << std::endl; }
void f2(const double x) { std::cout << "f2: " << x << std::endl; }
std::string f3(const int x) { std::cout << "f3: " << x << std::endl; return std::to_string(x + x); }
int main() {
index_call(0, std::make_tuple(42), f1, f2);
index_call(1, std::make_tuple(42), f1, f2);
const auto v1 = index_call(2, std::make_tuple(42), f1, f2, f3);
std::cout << boost::get<std::string>(v1) << std::endl;
const auto v2 = index_call(1, std::make_tuple(), std::bind(f3, 0), [] { std::cout << "lambda" << std::endl; return 42; });
std::cout << boost::get<int>(v2) << std::endl;
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment