C++中事件机制的简洁实现

事件模型是被广泛使用的好东西,但是C++标准库里没有现成的,其他实现又复杂或者不优雅,比如需要使用宏。现在VC11可以用在XP下了,那么就痛快的拿起C++11提供的先进设施组合出一个轻便的实现吧。

  为了达到简洁的目的,需要放弃一些特性:

  1、不支持判断函数是否已经绑定过(因为std::function不提供比较方法,自己实现function的话代码又变多了)

  2、需要使用者接收返回的回调函数标识来移除事件绑定(原因同上)

  3、事件没有返回值,不支持回调函数优先级、条件回调等事件高级特性(比如返回所有处理结果中的最大最小值;只回调与指定参数匹配的事件处理函数)

  4、事件参数理论上无限,实际上有限,一般支持0~10个参数(VC11还没有支持变长模板参数,GCC有了。不过可以通过缺省模板参数和偏特化来模拟,所以理论上无限制)

  5、不是线程安全的

  注:3、5两条可以通过引入策略模式来提供灵活支持,就像标准库和Loki做的那样,实现一个完整的事件机制。

 

最简单的实现

 1 #include <map>
 2 #include <functional>
 3 
 4 using namespace std;
 5 
 6 
 7 template<class Param1, class Param2>
 8 class Event
 9 {
10     typedef void HandlerT(Param1, Param2);
11     int m_handlerId;
12 
13 public:
14     Event() : m_handlerId(0) {}
15 
16     template<class FuncT> int addHandler(FuncT func)
17     {
18         m_handlers.emplace(m_handlerId, forward<FuncT>(func));
19         return m_handlerId++;
20     }
21 
22     void removeHandler(int handlerId)
23     {
24         m_handlers.erase(handlerId);
25     }
26 
27     void operator ()(Param1 arg1, Param2 arg2)
28     {
29         for ( const auto& i : m_handlers )
30             i.second(arg1, arg2);
31     }
32 
33 private:
34     map<int, function<HandlerT>> m_handlers;
35 };

addHandler把回调函数完美转发给std::function,让标准库来搞定各种重载,然后返回一个标识符用来注销绑定。试一下,工作的不错:

 1 void f1(int, int)
 2 {
 3     puts("f1()");
 4 }
 5 
 6 struct F2
 7 {
 8     void f(int, int)
 9     {
10         puts("f2()");
11     }
12 
13     void operator ()(int, int)
14     {
15         puts("f3()");
16     }
17 };
18 
19 int _tmain(int argc, _TCHAR* argv[])
20 {
21     Event<int, int> e;
22 
23     int id = e.addHandler(f1);
24 
25     e.removeHandler(id);
26 
27     using namespace std::placeholders;
28 
29     F2 f2;
30 
31     e.addHandler(bind(&F2::f, f2, _1, _2));
32     e.addHandler(bind(f2, _1, _2));
33 
34     e.addHandler([](int, int) {
35         puts("f4()");
36     });
37 
38     e(1, 2);
39 
40     return 0;
41 } 

虽然这里有一个小小的缺点,对于仿函数,如果想使用它的指针或引用是不可以直接绑定的,需要这样做: 

1 e.addHandler(ref(f2));
2 e.addHandler(ref(*pf2));    // pf2是指向f2的指针

  但是使用仿函数对象指针的情形不多,也不差多敲几个字符,何况在有Lambda表达式的情况下呢?

改进

1、有人不喜欢bind,用起来麻烦,放到addhandler里面去:

1         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
2         {
3             using namespace std::placeholders;
4             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
5             return m_handlerId++;
6         }

 2、扩展参数个数。没有变长模板参数,变通一下:

 1 struct NullType {};
 2 
 3 template<class P1 = Private::NullType, class P2 = Private::NullType>
 4 class Event 
 5 {
 6 public:
 7     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 8     {
 9         using namespace std::placeholders;
10         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
11         return m_handlerId++;
12     }
13 
14     void operator ()(P1 arg1, P2 arg2)
15     {
16         for ( const auto& i : m_handlers )
17             i.second(arg1, arg2);
18     }
19 };
20 
21 template<>
22 class Event<Private::NullType, Private::NullType>
23 {
24 public:
25     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
26     {
27         using namespace std::placeholders;
28         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj)));
29         return m_handlerId++;
30     }
31 
32     void operator ()()
33     {
34         for ( const auto& i : m_handlers )
35             i.second();
36     }
37 };
38 
39 template<class P1>
40 class Event<P1, Private::NullType>
41 {
42 public:
43     template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
44     {
45         using namespace std::placeholders;
46         m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1));
47         return m_handlerId++;
48     }
49 
50     void operator ()(P1 arg1)
51     {
52         for ( const auto& i : m_handlers )
53             i.second(arg1);
54     }
55 };

现在支持0~2个参数了。注意到各个模板里有公共代码,提取出来放进基类,然后要做的就是打开文本生成器了

补充一下:VC里std::function默认最多5个参数,最多支持10个,要在编译开关里设置一下宏_VARIADIC_MAX=10

 

完整代码

代码下载

View Code
  1 #pragma once
  2 
  3 #include <map>
  4 #include <functional>
  5 
  6 
  7 namespace Utility
  8 {
  9     namespace Private
 10     {
 11         struct NullType {};
 12 
 13         template<class HandlerT>
 14         class EventBase
 15         {
 16         public:
 17             EventBase() : m_handlerId(0) {}
 18 
 19             template<class FuncT> int addHandler(FuncT func)
 20             {
 21                 m_handlers.emplace(m_handlerId, std::forward<FuncT>(func));
 22                 return m_handlerId++;
 23             }
 24 
 25             void removeHandler(int handlerId)
 26             {
 27                 m_handlers.erase(handlerId);
 28             }
 29 
 30         protected:
 31             int m_handlerId;
 32             std::map<int, std::function<HandlerT>> m_handlers;
 33         };
 34     }
 35 
 36     template<class P1 = Private::NullType, class P2 = Private::NullType, class P3 = Private::NullType, class P4 = Private::NullType, class P5 = Private::NullType, class P6 = Private::NullType, class P7 = Private::NullType, class P8 = Private::NullType, class P9 = Private::NullType, class P10 = Private::NullType>
 37     class Event 
 38         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>
 39     {
 40     public:
 41         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)>::addHandler;
 42 
 43         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 44         {
 45             using namespace std::placeholders;
 46             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9, _10));
 47             return m_handlerId++;
 48         }
 49 
 50         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9, P10 arg10)
 51         {
 52             for ( const auto& i : m_handlers )
 53                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9, arg10);
 54         }
 55     };
 56 
 57     template<>
 58     class Event<Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
 59         : public Private::EventBase<void ()>
 60     {
 61     public:
 62         using Private::EventBase<void ()>::addHandler;
 63 
 64         template<class ObjT, class FuncT> int addHandler(ObjT const obj, FuncT func)
 65         {
 66             m_handlers.emplace(m_handlerId, std::bind(func, obj));
 67             return m_handlerId++;
 68         }
 69 
 70         void operator ()()
 71         {
 72             for ( const auto& i : m_handlers )
 73                 i.second();
 74         }
 75     };
 76 
 77     template<class P1>
 78     class Event<P1, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
 79         : public Private::EventBase<void (P1)>
 80     {
 81     public:
 82         using Private::EventBase<void (P1)>::addHandler;
 83 
 84         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
 85         {
 86             using namespace std::placeholders;
 87             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1));
 88             return m_handlerId++;
 89         }
 90 
 91         void operator ()(P1 arg1)
 92         {
 93             for ( const auto& i : m_handlers )
 94                 i.second(arg1);
 95         }
 96     };
 97 
 98     template<class P1, class P2>
 99     class Event<P1, P2, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
100         : public Private::EventBase<void (P1, P2)>
101     {
102     public:
103         using Private::EventBase<void (P1, P2)>::addHandler;
104 
105         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
106         {
107             using namespace std::placeholders;
108             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2));
109             return m_handlerId++;
110         }
111 
112         void operator ()(P1 arg1, P2 arg2)
113         {
114             for ( const auto& i : m_handlers )
115                 i.second(arg1, arg2);
116         }
117     };
118 
119     template<class P1, class P2, class P3>
120     class Event<P1, P2, P3, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
121         : public Private::EventBase<void (P1, P2, P3)>
122     {
123     public:
124         using Private::EventBase<void (P1, P2, P3)>::addHandler;
125 
126         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
127         {
128             using namespace std::placeholders;
129             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3));
130             return m_handlerId++;
131         }
132 
133         void operator ()(P1 arg1, P2 arg2, P3 arg3)
134         {
135             for ( const auto& i : m_handlers )
136                 i.second(arg1, arg2, arg3);
137         }
138     };
139 
140     template<class P1, class P2, class P3, class P4>
141     class Event<P1, P2, P3, P4, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
142         : public Private::EventBase<void (P1, P2, P3, P4)>
143     {
144     public:
145         using Private::EventBase<void (P1, P2, P3, P4)>::addHandler;
146 
147         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
148         {
149             using namespace std::placeholders;
150             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4));
151             return m_handlerId++;
152         }
153 
154         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4)
155         {
156             for ( const auto& i : m_handlers )
157                 i.second(arg1, arg2, arg3, arg4);
158         }
159     };
160 
161     template<class P1, class P2, class P3, class P4, class P5>
162     class Event<P1, P2, P3, P4, P5, Private::NullType, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
163         : public Private::EventBase<void (P1, P2, P3, P4, P5)>
164     {
165     public:
166         using Private::EventBase<void (P1, P2, P3, P4, P5)>::addHandler;
167 
168         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
169         {
170             using namespace std::placeholders;
171             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5));
172             return m_handlerId++;
173         }
174 
175         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5)
176         {
177             for ( const auto& i : m_handlers )
178                 i.second(arg1, arg2, arg3, arg4, arg5);
179         }
180     };
181 
182     template<class P1, class P2, class P3, class P4, class P5, class P6>
183     class Event<P1, P2, P3, P4, P5, P6, Private::NullType, Private::NullType, Private::NullType, Private::NullType>
184         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6)>
185     {
186     public:
187         using Private::EventBase<void (P1, P2, P3, P4, P5, P6)>::addHandler;
188 
189         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
190         {
191             using namespace std::placeholders;
192             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6));
193             return m_handlerId++;
194         }
195 
196         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6)
197         {
198             for ( const auto& i : m_handlers )
199                 i.second(arg1, arg2, arg3, arg4, arg5, arg6);
200         }
201     };
202 
203     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7>
204     class Event<P1, P2, P3, P4, P5, P6, P7, Private::NullType, Private::NullType, Private::NullType>
205         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7)>
206     {
207     public:
208         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7)>::addHandler;
209 
210         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
211         {
212             using namespace std::placeholders;
213             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7));
214             return m_handlerId++;
215         }
216 
217         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7)
218         {
219             for ( const auto& i : m_handlers )
220                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7);
221         }
222     };
223 
224     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8>
225     class Event<P1, P2, P3, P4, P5, P6, P7, P8, Private::NullType, Private::NullType>
226         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8)>
227     {
228     public:
229         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8)>::addHandler;
230 
231         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
232         {
233             using namespace std::placeholders;
234             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8));
235             return m_handlerId++;
236         }
237 
238         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8)
239         {
240             for ( const auto& i : m_handlers )
241                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8);
242         }
243     };
244 
245     template<class P1, class P2, class P3, class P4, class P5, class P6, class P7, class P8, class P9>
246     class Event<P1, P2, P3, P4, P5, P6, P7, P8, P9, Private::NullType>
247         : public Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9)>
248     {
249     public:
250         using Private::EventBase<void (P1, P2, P3, P4, P5, P6, P7, P8, P9)>::addHandler;
251 
252         template<class ObjT, class FuncT> int addHandler(ObjT obj, FuncT func)
253         {
254             using namespace std::placeholders;
255             m_handlers.emplace(m_handlerId, std::bind(func, std::forward<ObjT>(obj), _1, _2, _3, _4, _5, _6, _7, _8, _9));
256             return m_handlerId++;
257         }
258 
259         void operator ()(P1 arg1, P2 arg2, P3 arg3, P4 arg4, P5 arg5, P6 arg6, P7 arg7, P8 arg8, P9 arg9)
260         {
261             for ( const auto& i : m_handlers )
262                 i.second(arg1, arg2, arg3, arg4, arg5, arg6, arg7, arg8, arg9);
263         }
264     };
265 
266 
267 } // namespace Utility

 测试代码

各种绑定方式

View Code
  1 #include "Event.h"
  2 
  3 using namespace std;
  4 
  5 
  6 void f1(int, int)
  7 {
  8     puts("f1()");
  9 }
 10 
 11 struct F2
 12 {
 13     F2() { puts("F2 construct"); }
 14     F2(const F2 &) { puts("F2 copy"); }
 15     F2(F2 &&) { puts("F2 move"); }
 16     F2& operator=(const F2 &)  { puts("F2 copy assign"); return *this; }
 17     F2& operator=(F2 &&)  { puts("F2 move assign"); return *this; }
 18 
 19     void f(int, int)
 20     {
 21         puts("f2()");
 22     }
 23 
 24     void fc(int, int) const
 25     {
 26         puts("f2c()");
 27     }
 28 };
 29 
 30 struct F3
 31 {
 32     F3() { puts("F3 construct"); }
 33     F3(const F3 &) { puts("F3 copy"); }
 34     F3(F3 &&) { puts("F3 move"); }
 35     F3& operator=(const F3 &)  { puts("F3 copy assign"); return *this; }
 36     F3& operator=(F3 &&)  { puts("F3 move assign"); return *this; }
 37 
 38     void operator ()(int, int) const
 39     {
 40         puts("f3()");
 41     }
 42 };
 43 
 44 int _tmain(int argc, _TCHAR* argv[])
 45 {
 46     Utility::Event<int, int> e;
 47 
 48     // 一般函数
 49     e.addHandler(f1);
 50 
 51     int id = e.addHandler(&f1);                                    
 52     e.removeHandler(id);                                                // 移除事件处理函数
 53     
 54 
 55     // 成员函数
 56     using namespace std::placeholders;
 57 
 58     F2 f2;
 59     const F2 *pf2 = &f2;
 60 
 61     e.addHandler(bind(&F2::f, &f2, _1, _2));        // std::bind
 62     e.addHandler(&f2, &F2::f);
 63 
 64     e.addHandler(pf2, &F2::fc);                                    // 常量指针
 65     
 66     puts("----addHandler(f2, &F2::f)----");
 67     e.addHandler(f2, &F2::f);                                        // 对象拷贝构造
 68 
 69     puts("----addHandler(F2(), &F2::f)----");
 70     e.addHandler(F2(), &F2::f);                                    // 对象转移构造
 71 
 72     puts("--------");
 73 
 74 
 75     // 仿函数
 76     F3 f3;
 77     const F3 *pf3 = &f3;
 78 
 79     puts("----addHandler(f3)----");
 80     e.addHandler(f3);                                                        // 对象拷贝构造
 81 
 82     puts("----addHandler(F3())----");
 83     e.addHandler(F3());                                                    // 对象转移构造
 84     puts("--------");
 85 
 86     e.addHandler(ref(f3));                                            // 引用仿函数对象
 87     e.addHandler(ref(*pf3));                                        // 引用仿函数常量对象
 88 
 89     puts("--------");
 90 
 91     // Lambda表达式
 92     e.addHandler([](int, int) {
 93         puts("f4()");
 94     });
 95 
 96     // 激发事件
 97     e(1, 2);
 98 
 99     return 0;
100 }

 

转载于:https://www.cnblogs.com/lierlier/archive/2013/02/01/cppevent.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/294149.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Andorid之Log图文详解(Log.v,Log.d,Log.i,Log.w,Log.e)的用法总结

在调试代码的时候我们需要查看调试信息&#xff0c;那我们就需要用Android Log类。 android.util.Log常用的方法有以下5个&#xff1a;Log.v() Log.d() Log.i() Log.w() 以及 Log.e() 。根据首字母对应VERBOSE&#xff0c;DEBUG,INFO, WARN&#xff0c;ERROR。 1、Log.v 的调…

VS2010下的多线程窗口

多线程的调试一直是一个令人蛋疼的问题&#xff0c;一般的解决方法是写Log。有的时候想要直观地看一下线程的运行状态&#xff0c;简直是困难。幸好vs2010给我们提供了一个多线程窗口。 使用方式&#xff1a; 1、按F5进入调试状态下 2、按图1所示打开多线程窗口 图1 打开多线程…

Typora 开始收费, 不妨试试这个开源免费的MD编辑器

相信大家很多人都已经知道了, 最好用最受欢迎的 markdown 编辑器 - Typora, 从 1.0.0 版本已经开始收费, 根据其官网的介绍, 收费方式为买断制, 也就是一次付费永久使用, 价格是14.99 刀, 另外支持支付宝付款, 89 元人民币, 最多支持3台设备使用, 对于我来说, 算上家里和公司的…

linux+4.4+android,Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法

Ubuntu 14.04 x64配置Android 4.4 kitkat编译环境的方法跟Ubuntu 12.04 - 13.10 以及jellybean编译环境配置没多大区别, 顺便记录下而已:64位Ubuntu 11.10下Android开发环境的搭建(JDKEclipseADTAndroid SDK详细) http://www.linuxidc.com/Linux/2013-06/85303.htm一、配置依赖…

Blazor是春天还是寒风里的挣扎

title: Blazor是春天还是寒风里的挣扎 date: 2021-10-25 14:00:00 toc: true categories:- Blazor tags:- Blazor- MASA Blazor#官方解释BlazorBlazor允许您使用c#而不是JavaScript构建交互式web UI。Blazor应用由可重用的web UI组件组成&#xff0c;这些组件使用c#、HTML和CSS…

js个人笔记

2019独角兽企业重金招聘Python工程师标准>>> 看锋利的jquery第二版&#xff0c;&#xff0c;在前言的时候说建议使用最新版jquery&#xff0c;&#xff0c;然而在第二章结尾的地方有用到toggle()这个方法&#xff0c;&#xff0c;我自己用发现和书上的功能不同&…

linux ntfs 速度慢,将U盘磁盘格式改成NTFS解决u盘复制速度慢问题

1、我们首先要看看U盘的文件系统是哪个?打开计算机-可移动磁盘-右击属性。2、目前打多数U盘采用的都是FAT32格式&#xff0c;这也是大多数USB2.0船速速度比较慢的原因。我们先用文件大小测试一个它的读写速度&#xff0c;格子这里用的是一个大概四百兆的文件&#xff0c;为了让…

Android之进程与线程的讲解

安卓平台中当首次启动运行一个组件的时候&#xff0c;Android会相应的启动了一个进程。默认的&#xff0c;所有的组件和程序运行在这个进程和线程中&#xff0c;也可以安排组件在其他的进程或者线程中运行。 进程&#xff1a;组件运行的进程由manifest file控制。组件的节点 —…

Xamarin.Android和UWP之MVVM的简单使用(二)

0x01 前言 前面一篇&#xff0c;Xamarin.Android和UWP之MVVM的简单使用(一)&#xff0c;主要讲了MvvmLight的简单使用 这篇主要讲讲MvvmCross的简单使用&#xff0c;例子的话&#xff0c;还是和上篇的一样。直接进正题吧&#xff0c;不废话了。 0x02 简单的MVVM(mvvmcross) Dem…

ExtJs 带分页的comboBox

ExtJs 带分页的comboBox 如何得到当前第几页&#xff1f; 希望技术牛人能帮帮我&#xff0c;也可以加我扣扣【445958】&#xff0c; 交流JAVA Ext 框架等方面的技术&#xff01;转载于:https://blog.51cto.com/ajiao13/1133773

软件工程之个人项目--词频统计

不得不说对于菜鸟级的我&#xff0c;这是一次心酸的经历啊。。。自打接到王老师布置的这个任务&#xff08;个人项目&#xff09;之后&#xff0c;我心里一直在想着自己要用哪种语言来完成我的任务。以前多多少少写过一些程序的&#xff0c;这又想起了数据库小学期与永哥和小强…

史上最被低估的神级学科,看完忍不住感慨“它”也太重要了!

▲ 点击查看著名物理学家、数学家曾说&#xff1a;几何学的简洁美&#xff0c;却又是几何学之所以完美的核心存在。几何始于数学&#xff0c;但它的意义和影响却远超数学。一个个枯燥的数字和一个个简单的图形&#xff0c;却可以帮助我们解决很多问题&#xff0c;了解自然的规律…

.NET6之MiniAPI(三):Response

MiniAPI中&#xff0c;Response的返回数据有三种格式&#xff0c;IResult&#xff0c;string&#xff0c;json&#xff1a;ValueTask<string> - 这包括 string 和 Task<string>T&#xff08;任何其他类型&#xff0c;返回前端时转成json&#xff09;- 这包括 Task&…

ffmpeg speex转换为mp3或者aac

2019独角兽企业重金招聘Python工程师标准>>> 输入&#xff1a; flv格式&#xff0c;视频264编码&#xff0c;音频speex编码 -8:[rootandrew ffmpeg-3.0./ffprobe test_speex1.flv 32:ffprobe version 3.0-static32: Copyright (c) 2007-2016 the FFmpeg developers3…

c语言给bmp图片加滤镜,关于BMP位图透明通道的详解制作教程, 教你输出透明的BMP位图...

我是sjmhiex啊月谢谢大家的支持 百度贴吧&#xff1a;sjmhiex吧QQ群&#xff1a;243153684BMP支持透明比较常见的方法有两种&#xff1a; 一种是32位图&#xff0c;直接就可以是透明的&#xff0c;还可以是半透明效果&#xff0c;一般都是用PNG转成的&#xff0c;或者在保存图…

Android之Lollipop DevicePolicyManager学习(上)

Android 5.0(lollipop)发布之后&#xff0c;看特性文档增加了不少有趣的东西。 最近花了一些时间&#xff0c;研究了下其中Managed Profile的概念&#xff0c;简称MP&#xff0c;记录下来作为一些经验&#xff0c;有需要的同学请参考。 简介 Managed Profile&#xff0c;简称被…