Skip to content

Instantly share code, notes, and snippets.

@quartorz
Last active December 30, 2015 14:09
Show Gist options
  • Save quartorz/7840245 to your computer and use it in GitHub Desktop.
Save quartorz/7840245 to your computer and use it in GitHub Desktop.
#include <tuple>
#include <iostream>
#include <cstddef>
template <std::size_t... I>
class index_tuple{
public:
using type = index_tuple<I...>;
};
template <class Left, class Right>
class concat_impl;
template <std::size_t... Left, std::size_t... Right>
class concat_impl<index_tuple<Left...>, index_tuple<Right...>>
: public index_tuple<Left..., Right...>
{
};
template <class Left, class Right>
using concat = typename concat_impl<Left, Right>::type;
template <class Sequence, std::size_t N>
class shift_impl;
template <std::size_t N, std::size_t... I>
class shift_impl<index_tuple<I...>, N>
: public index_tuple<(I + N)...>
{
};
template <class Sequence, std::size_t N>
using shift = typename shift_impl<Sequence, N>::type;
template <std::size_t Begin, std::size_t End>
class make_index_range_impl;
template <std::size_t Begin, std::size_t End>
using make_index_range = typename make_index_range_impl<Begin, End>::type;
template <std::size_t Begin, std::size_t End>
class make_index_range_impl:
public shift< concat<
make_index_range<0, (End - Begin) / 2>,
shift<make_index_range<0, (End - Begin) / 2 + (End - Begin) % 2>, (End - Begin) / 2>
>, Begin>
{
};
template <>
class make_index_range_impl<0, 1>: public index_tuple<0>
{
};
template <>
class make_index_range_impl<0, 0>: public index_tuple<>
{
};
template <std::size_t N>
using make_index = make_index_range<0, N>;
class nil{
public:
template <class T>
void operator=(const T&)
{
}
template <class T>
operator T()
{
return T();
}
};
template <class... Functions>
class combiner{
template <class Function, class... Args>
class result{
using result_type = typename std::result_of<Function(Args...)>::type;
public:
using type = typename std::conditional<std::is_void<result_type>::value, nil, result_type>::type;
};
template <class... Args>
using get_result_tuple = std::tuple<typename result<Functions, Args...>::type...>;
using function_tuple = std::tuple<Functions...>;
function_tuple functions;
public:
combiner(Functions... functions): functions(functions...)
{
}
template <class... Args>
get_result_tuple<Args...> operator()(Args... args)
{
return operator_helper(make_index<sizeof...(Functions)>(), args...);
}
private:
template <std::size_t... Indices, class... Args>
get_result_tuple<Args...> operator_helper(index_tuple<Indices...>, Args... args)
{
return get_result_tuple<Args...>(bind<Indices>(args...)...);
}
template <std::size_t I, class... Args>
typename std::tuple_element<I, get_result_tuple<Args...>>::type bind(Args... args)
{
using result_type = typename std::tuple_element<I, get_result_tuple<Args...>>::type;
return bind_helper<result_type>(std::get<I>(functions), args...);
}
template <class Result, class Function, class... Args>
class bind_helper_class{
Result result;
public:
bind_helper_class(Function &f, Args... args): result(f(args...))
{
}
operator Result()
{
return result;
}
};
template <class Function, class... Args>
class bind_helper_class<nil, Function, Args...>{
public:
bind_helper_class(Function &f, Args... args)
{
f(args...);
}
operator nil()
{
return nil();
}
};
template <class Result, class Function, class... Args>
bind_helper_class<Result, Function, Args...> bind_helper(Function &f, Args... args)
{
return bind_helper_class<Result, Function, Args...>(f, args...);
}
};
template <class... Functions>
combiner<Functions...> make_combiner(Functions... functions)
{
return combiner<Functions...>(functions...);
}
double function(int x, double y)
{
return x * y;
}
class Class{
public:
int operator()(int x, double)
{
return x;
}
};
int main()
{
auto combiner = make_combiner(function, Class(), [](int, double){});
double a;
int b;
std::tie(a, b, std::ignore) = combiner(10, 20.);
std::cout << a << ' ' << b << std::endl;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment