4
4
#include < type_traits>
5
5
#include < tuple>
6
6
7
+ #include " is_reference_wrapper.hpp"
7
8
#include " invoke.hpp"
8
9
9
- template <class T , class UnBoundArgTpl >
10
- constexpr T& get_final_args (std::reference_wrapper<T> tid, UnBoundArgTpl&& unbound_args) {
11
- return tid.get ();
12
- }
10
+ template <class TiD ,
11
+ bool = is_reference_wrapper_v<TiD>,
12
+ bool = std::is_bind_expression_v<TiD>,
13
+ bool = ((std::is_placeholder_v<TiD>) > 0 )>
14
+ struct BoundArgument ;
13
15
14
- template <class cvTiD , class UnBoundArgTpl ,
15
- std::enable_if_t <std::is_bind_expression_v<std::remove_cv_t <cvTiD>>>* = nullptr >
16
- constexpr decltype (auto ) get_final_args(cvTiD& tid, UnBoundArgTpl&& unbound_args) {
17
- return std::apply (tid, std::move (unbound_args));
18
- }
19
-
20
- template <class cvTiD , class UnBoundArgTpl ,
21
- int idx = std::is_placeholder_v<std::remove_cv_t <cvTiD>>,
22
- std::enable_if_t <(idx > 0 )>* = nullptr >
23
- constexpr decltype (auto ) get_final_args(cvTiD& tid, UnBoundArgTpl&& unbound_args)
24
- {
25
- return std::get<idx - 1 >(unbound_args);
26
- }
16
+ template <class TiD >
17
+ struct BoundArgument <TiD, true , false , false > {
18
+ template <class cvTiD , class ... Uj>
19
+ static constexpr auto value (cvTiD& tid, Uj&&...)
20
+ -> typename TiD::type&
21
+ {
22
+ static_assert (std::is_same_v<std::remove_cv_t <cvTiD>, TiD>);
23
+ return tid.get ();
24
+ }
25
+ template <class ...>
26
+ using type = typename TiD::type&;
27
+ template <class ...>
28
+ using const_type = typename TiD::type&;
29
+ };
27
30
28
- template <class cvTiD , class UnBoundArgTpl ,
29
- std::enable_if_t <!std::is_bind_expression_v<std::remove_cv_t <cvTiD>> &&
30
- std::is_placeholder_v<std::remove_cv_t <cvTiD>> <= 0 >* = nullptr >
31
- constexpr cvTiD& get_final_args (cvTiD& tid, UnBoundArgTpl&& unbound_args)
32
- {
33
- return tid;
34
- }
31
+ template <class TiD >
32
+ struct BoundArgument <TiD, false , true , false > {
33
+ template <class cvTiD , class ... Uj>
34
+ static constexpr auto value (cvTiD& tid, Uj&&... uj)
35
+ -> std::result_of_t<cvTiD& (Uj&&...)>
36
+ {
37
+ static_assert (std::is_same_v<std::remove_cv_t <cvTiD>, TiD>);
38
+ return tid (std::forward<Uj>(uj)...);
39
+ }
40
+ template <class ... Uj>
41
+ using type = std::result_of_t <TiD& (Uj&&...)>;
42
+ template <class ... Uj>
43
+ using const_type = std::result_of_t <TiD const & (Uj&&...)>;
44
+ };
45
+
46
+ template <class TiD >
47
+ struct BoundArgument <TiD, false , false , true > {
48
+ static constexpr int position { std::is_placeholder_v<TiD> - 1 };
49
+ template <class cvTiD , class ... Uj>
50
+ static constexpr auto value (cvTiD& tid, Uj&&... uj)
51
+ -> std::tuple_element_t<position,std::tuple<Uj...>>
52
+ {
53
+ static_assert (std::is_same_v<std::remove_cv_t <cvTiD>, TiD>);
54
+ return std::get<position>(std::forward_as_tuple (std::forward<Uj>(uj)...));
55
+ }
56
+ template <class ... Uj>
57
+ using type = std::tuple_element_t <position,std::tuple<Uj...>>;
58
+ template <class ... Uj>
59
+ using const_type = std::tuple_element_t <position,std::tuple<Uj...>>;
60
+ };
61
+
62
+ template <class TiD >
63
+ const int BoundArgument<TiD, false , false , true >::position;
64
+
65
+ template <class TiD , bool , bool , bool >
66
+ struct BoundArgument {
67
+ template <class cvTiD , class ... Uj>
68
+ static constexpr auto value (cvTiD& tid, Uj&&...)
69
+ -> cvTiD&
70
+ {
71
+ static_assert (std::is_same_v<std::remove_cv_t <cvTiD>, TiD>);
72
+ return tid;
73
+ }
74
+ template <class ...>
75
+ using type = TiD&;
76
+ template <class ...>
77
+ using const_type = TiD const &;
78
+ };
35
79
36
80
template <class FD , class R , class ... BoundArgs>
37
81
struct Bind {
38
82
FD fd;
39
- std::tuple<std:: decay_t < BoundArgs> ...> bound_args;
83
+ std::tuple<BoundArgs...> bound_args;
40
84
private:
41
85
template <class cvFD , class BoundArgTpl , class ... UnBoundArgs, std::size_t ... idx,
42
- class T = R, std::enable_if_t <std::is_same_v<T,void (void )>>* = nullptr >
43
- static constexpr decltype (auto ) unwrap_bound_args (cvFD& fd,
86
+ class T = R, std::enable_if_t <std::is_same_v<T,void (void )>, int > = 0 >
87
+ static constexpr decltype (auto ) unpack_bound_args (cvFD& fd,
44
88
/* cv std::tuple<TiD...>& */ BoundArgTpl& bound_args,
45
89
std::index_sequence<idx...>,
46
- /* std::tuple<Vi&&...>&& */ std::tuple< UnBoundArgs...>&& unbound_args
90
+ UnBoundArgs&& ... unbound_args
47
91
) {
48
- return (invoke)(fd,(get_final_args)(std::get<idx>(bound_args), std::move (unbound_args))...);
92
+ return (invoke)(fd, BoundArgument<BoundArgs>::value (std::get<idx>(bound_args),
93
+ std::forward<UnBoundArgs>(unbound_args)...)...);
49
94
}
50
95
template <class cvFD , class BoundArgTpl , class ... UnBoundArgs, std::size_t ... idx,
51
- class T = R, std::enable_if_t <!std::is_same_v<T,void (void )>>* = nullptr >
52
- static constexpr T unwrap_bound_args (cvFD& fd,
96
+ class T = R, std::enable_if_t <!std::is_same_v<T,void (void )>, int > = 0 >
97
+ static constexpr T unpack_bound_args (cvFD& fd,
53
98
/* cv std::tuple<TiD...>& */ BoundArgTpl& bound_args,
54
99
std::index_sequence<idx...>,
55
- /* std::tuple<Vi&&...>&& */ std::tuple< UnBoundArgs...>&& unbound_args
100
+ UnBoundArgs&& ... unbound_args
56
101
) {
57
- return (invoke<T>)(fd,(get_final_args)(std::get<idx>(bound_args), std::move (unbound_args))...);
102
+ return (invoke<T>)(fd,BoundArgument<BoundArgs>::value (std::get<idx>(bound_args),
103
+ std::forward<UnBoundArgs>(unbound_args)...)...);
58
104
}
59
105
public:
60
106
template <class ... UnBoundArgs>
61
107
constexpr decltype (auto ) operator()(UnBoundArgs&&... unbound_args) {
62
- return unwrap_bound_args (fd, bound_args,
108
+ static_assert (
109
+ std::is_callable_v<
110
+ FD& (typename BoundArgument<BoundArgs>::template type<UnBoundArgs&&...>...)
111
+ >,
112
+ " The target object is not callable with the given arguments."
113
+ );
114
+ return unpack_bound_args (fd, bound_args,
63
115
std::index_sequence_for<BoundArgs...>{},
64
- std::forward_as_tuple (std:: forward<UnBoundArgs>(unbound_args)...) );
116
+ std::forward<UnBoundArgs>(unbound_args)...);
65
117
}
66
118
67
119
template <class ... UnBoundArgs>
68
120
constexpr decltype (auto ) operator()(UnBoundArgs&&... unbound_args) const {
69
- return unwrap_bound_args (fd, bound_args,
121
+ static_assert (
122
+ std::is_callable_v<
123
+ FD const & (typename BoundArgument<BoundArgs>::template const_type<UnBoundArgs&&...>...)
124
+ >,
125
+ " The target object is not callable with the given arguments."
126
+ );
127
+ return unpack_bound_args (fd, bound_args,
70
128
std::index_sequence_for<BoundArgs...>{},
71
- std::forward_as_tuple (std:: forward<UnBoundArgs>(unbound_args)...) );
129
+ std::forward<UnBoundArgs>(unbound_args)...);
72
130
}
73
131
};
74
132
@@ -80,15 +138,15 @@ namespace std {
80
138
}
81
139
82
140
template <class F , class ... BoundArgs>
83
- constexpr Bind<std::decay_t <F>, void (void ), BoundArgs...>
84
- bind (F&& f, BoundArgs&&... bound_args)
141
+ constexpr Bind<std::decay_t <F>, void (void ), std:: decay_t < BoundArgs> ...>
142
+ bind (F&& f, BoundArgs&&... bound_args)
85
143
{
86
144
return { std::forward<F>(f), { std::forward<BoundArgs>(bound_args)... } };
87
145
}
88
146
89
147
template <class R , class F , class ... BoundArgs>
90
- constexpr Bind<std::decay_t <F>, R, BoundArgs...>
91
- bind (F&& f, BoundArgs&&... bound_args)
148
+ constexpr Bind<std::decay_t <F>, R, std:: decay_t < BoundArgs> ...>
149
+ bind (F&& f, BoundArgs&&... bound_args)
92
150
{
93
151
return { std::forward<F>(f), { std::forward<BoundArgs>(bound_args)... } };
94
152
}
0 commit comments