Skip to content

Instantly share code, notes, and snippets.

@talybin
Last active November 21, 2019 00:25
Show Gist options
  • Select an option

  • Save talybin/d380f52e7dc385fde3abdc730edd9b05 to your computer and use it in GitHub Desktop.

Select an option

Save talybin/d380f52e7dc385fde3abdc730edd9b05 to your computer and use it in GitHub Desktop.
A scetch. Needs optimization.
#include <iostream>
#include <functional>
#include <tuple>
#include <type_traits>
template <class T>
struct fn_signature
: fn_signature<decltype(std::function(std::declval<T>()))>
{ };
template <class T>
struct fn_signature<std::function<T>> : fn_signature<T>
{ };
template <class R, class... Args>
struct fn_signature<R(Args...)>
{
using return_type = R;
using type = R(Args...);
};
template <class F>
using ret_t = typename fn_signature<F>::return_type;
template <class F, class... Ts>
struct check_fn : std::true_type { };
template <class F, class T, class... Ts>
struct check_fn<F, T, Ts...> : check_fn<F, Ts...> { };
template <class F, class T>
//struct check_fn<F, T> : std::is_invocable<F, ret_t<T>> { };
struct check_fn<F, T> : std::conditional_t<
std::is_same_v<void, ret_t<T>>,
std::true_type,
std::is_invocable<F, ret_t<T>> > { };
template <class... Ts>
struct promise
{
promise() = default;
promise(std::tuple<Ts...>&& t)
: holder_(std::move(t))
{ }
template <class F>
promise<Ts..., F> then(F&& fn) const && {
static_assert(check_fn<F, Ts...>::value,
"F must accept previous function return value or do not accept anything");
return {
std::tuple_cat(
std::move(holder_),
std::tuple<F>(std::forward<F>(fn)))
};
}
void run() {
if constexpr (sizeof...(Ts) > 0)
run_impl(std::in_place_index<sizeof...(Ts)-1>);
}
private:
template <size_t N>
decltype(auto) run_impl(std::in_place_index_t<N>)
{
using Prev = std::tuple_element_t<N-1, std::tuple<Ts...>>;
if constexpr (std::is_same_v<void, ret_t<Prev>>) {
run_impl(std::in_place_index<N-1>);
return std::get<N>(holder_)();
}
else return std::get<N>(holder_)(
run_impl(std::in_place_index<N-1>));
}
decltype(auto) run_impl(std::in_place_index_t<0>) {
return std::get<0>(holder_)();
}
std::tuple<Ts...> holder_;
};
int main()
{
auto p = promise<>()
.then([]() {
std::cout << "1\n";
return 2;
})
.then([](int x) {
std::cout << x << '\n';
})
.then([]() {
std::cout << "taking void\n";
})
;
p.run();
/*
auto x = []() {
};
auto y = [](void) {
};
//y(x());
auto z = y();
*/
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment