|
2 | 2 |
|
3 | 3 | #include <functional> |
4 | 4 | #include <type_traits> |
5 | | -#include <experimental/tuple> |
| 5 | +#include <tuple> |
6 | 6 |
|
7 | 7 | template<class T, class UnBoundArgTpl> |
8 | | -constexpr T& get_final_args(std::reference_wrapper<T> tid, UnBoundArgTpl&& unbound_args) |
9 | | -{ |
| 8 | +constexpr T& get_final_args(std::reference_wrapper<T> tid, UnBoundArgTpl&& unbound_args) { |
10 | 9 | return tid.get(); |
11 | 10 | } |
12 | 11 |
|
13 | 12 | template<class cvTiD, class UnBoundArgTpl, |
14 | | - int idx = std::is_placeholder<std::remove_cv_t<cvTiD>>{}, |
| 13 | + std::enable_if_t<std::is_bind_expression_v<std::remove_cv_t<cvTiD>>>* = nullptr> |
| 14 | +constexpr decltype(auto) get_final_args(cvTiD& tid, UnBoundArgTpl&& unbound_args) { |
| 15 | + return std::apply(tid, std::move(unbound_args)); |
| 16 | +} |
| 17 | + |
| 18 | +template<class cvTiD, class UnBoundArgTpl, |
| 19 | + int idx = std::is_placeholder_v<std::remove_cv_t<cvTiD>>, |
15 | 20 | std::enable_if_t<(idx > 0)>* = nullptr> |
16 | 21 | constexpr decltype(auto) get_final_args(cvTiD& tid, UnBoundArgTpl&& unbound_args) |
17 | 22 | { |
18 | 23 | return std::get<idx - 1>(unbound_args); |
19 | 24 | } |
20 | 25 |
|
21 | 26 | template<class cvTiD, class UnBoundArgTpl, |
22 | | - std::enable_if_t<std::is_placeholder<std::remove_cv_t<cvTiD>>{} <= 0>* = nullptr> |
| 27 | + std::enable_if_t<!std::is_bind_expression_v<std::remove_cv_t<cvTiD>> && |
| 28 | + std::is_placeholder_v<std::remove_cv_t<cvTiD>> <= 0>* = nullptr> |
23 | 29 | constexpr cvTiD& get_final_args(cvTiD& tid, UnBoundArgTpl&& unbound_args) |
24 | 30 | { |
25 | 31 | return tid; |
26 | 32 | } |
27 | 33 |
|
28 | | -template<class F, class BoundArgTpl, std::size_t... idx, class UnBoundArgTpl> |
29 | | -decltype(auto) bind_apply_unwrap_bound_args(F& f, BoundArgTpl&& bound_args, std::index_sequence<idx...>, UnBoundArgTpl&& unbound_args) |
30 | | -{ |
31 | | - return f(get_final_args(std::get<idx>(bound_args), static_cast<UnBoundArgTpl&&>(unbound_args))...); |
32 | | -} |
33 | | - |
34 | | -template<class FD, class ArgTpl, class R = void(void)> |
| 34 | +template<class FD, class R, class... BoundArgs> |
35 | 35 | struct Bind { |
36 | 36 | FD fd; |
37 | | - ArgTpl bound_args; |
| 37 | + std::tuple<std::decay_t<BoundArgs>...> bound_args; |
38 | 38 | private: |
39 | | - static constexpr std::size_t arity = std::tuple_size<ArgTpl>{}; |
| 39 | + template<class cvFD, class BoundArgTpl, class... UnBoundArgs, std::size_t... idx> |
| 40 | + static constexpr decltype(auto) unwrap_bound_args(cvFD& fd, |
| 41 | + /* cv std::tuple<TiD...>& */ BoundArgTpl& bound_args, |
| 42 | + std::index_sequence<idx...>, |
| 43 | + /* std::tuple<Vi&&...>&& */ std::tuple<UnBoundArgs...>&& unbound_args |
| 44 | + ) { |
| 45 | + return fd((get_final_args)(std::get<idx>(bound_args), std::move(unbound_args))...); |
| 46 | + } |
40 | 47 | public: |
41 | 48 | template<class... UnBoundArgs> |
42 | | - constexpr auto operator()(UnBoundArgs&&... unbound_args) |
43 | | - { |
44 | | - return bind_apply_unwrap_bound_args(fd, bound_args, std::make_index_sequence<arity>{}, std::forward_as_tuple(std::forward<UnBoundArgs>(unbound_args)...)); |
| 49 | + constexpr decltype(auto) operator()(UnBoundArgs&&... unbound_args) { |
| 50 | + return unwrap_bound_args(fd, bound_args, |
| 51 | + std::index_sequence_for<BoundArgs...>{}, |
| 52 | + std::forward_as_tuple(std::forward<UnBoundArgs>(unbound_args)...)); |
45 | 53 | } |
46 | 54 |
|
47 | 55 | template<class... UnBoundArgs> |
48 | | - constexpr auto operator()(UnBoundArgs&&... unbound_args) const |
49 | | - { |
50 | | - return bind_apply_unwrap_bound_args(fd, bound_args, std::make_index_sequence<arity>{}, std::forward_as_tuple(std::forward<UnBoundArgs>(unbound_args)...)); |
| 56 | + constexpr decltype(auto) operator()(UnBoundArgs&&... unbound_args) const { |
| 57 | + return unwrap_bound_args(fd, bound_args, |
| 58 | + std::index_sequence_for<BoundArgs...>{}, |
| 59 | + std::forward_as_tuple(std::forward<UnBoundArgs>(unbound_args)...)); |
51 | 60 | } |
52 | 61 | }; |
53 | 62 |
|
| 63 | +namespace std { |
| 64 | + template<class FD, class R, class... BoundArgs> |
| 65 | + struct is_bind_expression<Bind<FD, R, BoundArgs...>> : true_type {}; |
| 66 | +} |
| 67 | + |
54 | 68 | template<class F, class... BoundArgs> |
55 | | -constexpr Bind<std::decay_t<F>, std::tuple<std::decay_t<BoundArgs>...>> |
| 69 | +constexpr Bind<std::decay_t<F>, void(void), BoundArgs...> |
56 | 70 | bind(F&& f, BoundArgs&&... bound_args) |
57 | 71 | { |
58 | 72 | return { std::forward<F>(f), { std::forward<BoundArgs>(bound_args)... } }; |
59 | 73 | } |
60 | 74 |
|
61 | 75 | template<class R, class F, class... BoundArgs> |
62 | | -constexpr Bind<std::decay_t<F>, std::tuple<std::decay_t<BoundArgs>...>, R> |
| 76 | +constexpr Bind<std::decay_t<F>, R, BoundArgs...> |
63 | 77 | bind(F&& f, BoundArgs&&... bound_args) |
64 | 78 | { |
65 | 79 | return { std::forward<F>(f), { std::forward<BoundArgs>(bound_args)... } }; |
|
0 commit comments