C++ STL 内 std::{bind/tuple/function} 简单实现

时间:2021-09-15 06:42:25

基本逻辑思考

首先是实现 function,这个比较简单,重载 operator() 就好,这里只实现对函数指针的包装

其次是实现 tuple,这个会比较绕,通过模板取第一个参数,然后用剩下的参数继续生成  tuple并继承,是一种递归的思想

有了 tuple 就要有 get(),这个就更比较绕了,首先是需要类似的方式实现获得 tuple 的值类型与元组类型,然后通过强制类型转换,获取对应的层级的 value

接下来是 bind,首先要解决的就是如何保存创建时的参数列表,这里就用到 tuple 来保存了

奇技淫巧还是运行函数时取相应的元组的对应位置的值,还是类似的方式,通过特化模板,公式是  <n, indexs...> => <n - 1, n - 1, indexs...>,比如 3 最后会生成 0 0 1 2 那么抛弃第一个,并用来展开元组,传递给函数指针

最重要的来了,就是如何实现 placeholders,简单来说就是在上一步的 operator() 增加传入参数,并制造成元组 r_args,然后带进一个 _unwrap_tuple 类,这里会重载 operator[] 根据传入数据结构,如果是 _placeholders<index> 那么取 r_args 相应的 index 位置,否则会直接  return

代码

不多说,还是直接放代码,仅作为参考,有写的不好的地方轻喷

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
/*
 * Author: SpringHack - springhack@live.cn
 * Last modified: 2020-02-19 10:16:17
 * Filename: main.cpp
 * Description: Created by SpringHack using vim automatically.
 */
#include <iostream>
 
namespace dosk { // begin namespace dosk
 
// function
template <typename... T>
class function;
 
template <typename Result, typename... Args>
class function<Result(Args...)> {
 private:
  Result (*function_)(Args...);
 public:
  typedef Result return_type;
  function() = default;
  function(Result (*fn)(Args...)) : function_(fn) {};
  Result operator()(Args... a) {
   return function_(a...);
  }
  function& operator=(Result (*fn)(Args...)) {
   function_ = fn;
   return *this;
  }
};
 
// tuple
template <typename... T>
class tuple;
 
template <typename HEAD, typename... LIST>
class tuple<HEAD, LIST...> : public tuple<LIST...> {
 public:
  HEAD value;
  tuple(HEAD head, LIST... list) : tuple<LIST...>(list...), value(head) {};
};
 
template <>
class tuple<> {};
 
// tuple get
template <int index, typename... T>
class _tuple_type;
 
template <int index, typename HEAD, typename... LIST>
class _tuple_type<index, tuple<HEAD, LIST...>> {
 public:
  typedef typename _tuple_type<index - 1, tuple<LIST...>>::value_type value_type;
  typedef typename _tuple_type<index - 1, tuple<LIST...>>::tuple_type tuple_type;
};
 
template <typename HEAD, typename... LIST>
class _tuple_type<0, tuple<HEAD, LIST...>> {
 public:
  typedef HEAD value_type;
  typedef tuple<HEAD, LIST...> tuple_type;
};
 
template <int index, typename HEAD, typename... LIST>
typename _tuple_type<index, tuple<HEAD, LIST...>>::value_type get(tuple<HEAD, LIST...> t) {
 typedef typename _tuple_type<index, tuple<HEAD, LIST...>>::value_type value_type;
 typedef typename _tuple_type<index, tuple<HEAD, LIST...>>::tuple_type tuple_type;
 value_type rv = ((tuple_type)t).value;
 return rv;
}
 
// bind
template <size_t...>
class _tuple_index {};
 
template <size_t n, size_t... indexs>
class _make_indexs : public _make_indexs<n - 1, n - 1, indexs...> {};
 
template<size_t... indexs>
class _make_indexs<0, indexs...> {
 public:
  typedef _tuple_index<indexs...> index_type;
};
 
namespace placeholders {
 
template <size_t index>
class _placeholders {};
 
_placeholders<0> _1;
_placeholders<1> _2;
_placeholders<2> _3;
_placeholders<3> _4;
_placeholders<4> _5;
_placeholders<5> _6;
_placeholders<6> _7;
_placeholders<7> _8;
_placeholders<8> _9;
_placeholders<9> _10;
 
template <typename... RArgs>
class _unwrap_tuple {
 public:
  tuple<RArgs...> r_args;
  _unwrap_tuple(tuple<RArgs...> r_args) : r_args(r_args) {};
  template <typename R>
  R operator[](R r) {
   return r;
  }
  template <size_t index>
  auto operator[](placeholders::_placeholders<index>) {
   return get<index>(r_args);
  }
};
 
};
 
template <typename Func, typename... Args>
class bind_t {
 public:
  typedef typename _make_indexs<sizeof...(Args)>::index_type _indexs;
  typedef typename Func::return_type return_type;
  Func func;
  tuple<Args...> args;
  bind_t(Func func, Args... args): func(func), args(args...) {}
  template <typename... RArgs>
  return_type operator()(RArgs&&... _r_args) {
   tuple<RArgs...> r_args = tuple<RArgs...>(_r_args...);
   return run(_indexs(), r_args);
  }
  template <size_t... Idx, typename... RArgs>
  return_type run(_tuple_index<Idx...>, tuple<RArgs...> r_args) {
   return func(unwrap_args<Idx>(r_args)...);
  }
  template <size_t index, typename... RArgs>
  auto unwrap_args(tuple<RArgs...> r_args) {
   placeholders::_unwrap_tuple<RArgs...> _u_a(r_args);
   auto _m_a = get<index>(args);
   return _u_a[_m_a];
  }
};
 
template <typename Func, typename... Args>
bind_t<Func, Args...> bind(Func& func, Args&&... args) {
 return bind_t<Func, Args...>(func, args...);
}
 
}; // end namespace dosk
 
 
 
// Test code
std::string test_func(int a, const char * b) {
 return std::to_string(a) + std::string(b);
}
 
std::string test_bind_args(int a, int b, int c, int d, int e) {
 return std::to_string(a) + std::to_string(b) + std::to_string(c) + std::to_string(d) + std::to_string(e);
}
 
int main() {
 // Test tuple
 dosk::tuple<int, const char *> t(123, "456");
 std::cout << dosk::get<0>(t) << dosk::get<1>(t) << std::endl;
 // Test function
 dosk::function<std::string(int, const char *)> closure_1 = test_func;
 std::cout << closure_1(123, "456") << std::endl;
 // Test bind
 dosk::function<std::string(int, int, int, int, int)> closure_2 = test_bind_args;
 auto binder = dosk::bind(closure_2, 1, dosk::placeholders::_2, 3, dosk::placeholders::_1, 5);
 std::cout << binder(4, 2, 0) << std::endl;
 return 0;
}

到此这篇关于C++ STL 内 std::{bind/tuple/function} 简单实现的文章就介绍到这了,更多相关C++  std::{bind/tuple/function}内容请搜素服务器之家以前的文章或下面相关文章,希望大家以后多多支持服务器之家!

原文链接:https://www.dosk.win/2020/02/19/fake-stl-bind-tuple-function/