Last active
December 30, 2015 14:09
-
-
Save quartorz/7840245 to your computer and use it in GitHub Desktop.
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 <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