当前位置: 移动技术网 > IT编程>开发语言>C/C++ > 【转】tars源码漫谈第1篇------tc_loki.h (牛逼哄哄的loki库)

【转】tars源码漫谈第1篇------tc_loki.h (牛逼哄哄的loki库)

2018年10月26日  | 移动技术网IT编程  | 我要评论

6月6日是什么节日,聚发财,和美女睡觉小游戏

loki库是c++模板大牛andrei写的, 里面大量运用模板的特性, 而tc_loki.h借用了loki库的部分代码, 形成了一个基本的文件tc_loki.h, 来看看:

  1 #ifndef __tc_typetraits_h
  2 #define __tc_typetraits_h
  3  
  4 #include <memory>
  5  
  6 namespace tars
  7 {
  8 /////////////////////////////////////////////////
  9 // 说明: loki            
 10 /////////////////////////////////////////////////
 11  
 12 namespace tl
 13 {
 14     //只声明, 不定义的类, 作为typelist的末端类型
 15     class nulltype;
 16  
 17     //空类型
 18     struct emptytype { };
 19  
 20     /**
 21      * 数值到类型的映射
 22      */
 23     template<int v>
 24     struct int2type
 25     {
 26        enum { value = v };
 27     };
 28  
 29     /**
 30      * 类型到类型的映射
 31      */
 32     template<typename t>
 33     struct type2type
 34     {
 35         typedef t originaltype;
 36     };
 37  
 38     ///////////////////////////////////////////////////////////////////////////
 39     // 以下是typelist的定义(目前只支持10个参数)
 40     /**
 41      * 定义类型链表
 42     */
 43     template<typename head, typename tail>
 44     struct typelist
 45     {
 46         typedef head h;
 47         typedef tail t;
 48     };
 49  
 50     #define typelist_1(t1) typelist<t1, tl::nulltype>
 51     #define typelist_2(t1, t2) typelist<t1, tl::typelist_1(t2)>
 52     #define typelist_3(t1, t2, t3) typelist<t1, tl::typelist_2(t2, t3)>
 53     #define typelist_4(t1, t2, t3, t4) typelist<t1, tl::typelist_3(t2, t3, t4)>
 54     #define typelist_5(t1, t2, t3, t4, t5) typelist<t1, tl::typelist_4(t2, t3, t4, t5)>
 55     #define typelist_6(t1, t2, t3, t4, t5, t6) typelist<t1, tl::typelist_5(t2, t3, t4, t5, t6)>
 56     #define typelist_7(t1, t2, t3, t4, t5, t6, t7) typelist<t1, tl::typelist_6(t2, t3, t4, t5, t6, t7)>
 57     #define typelist_8(t1, t2, t3, t4, t5, t6, t7, t8) typelist<t1, tl::typelist_7(t2, t3, t4, t5, t6, t7, t8)>
 58     #define typelist_9(t1, t2, t3, t4, t5, t6, t7, t8, t9) typelist<t1, tl::typelist_8(t2, t3, t4, t5, t6, t7, t8, t9)>
 59     #define typelist_10(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10) typelist<t1, tl::typelist_9(t2, t3, t4, t5, t6, t7, t8, t9, t10)>
 60     #define typelist_11(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11) typelist<t1, tl::typelist_10(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11)>
 61     #define typelist_12(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12) typelist<t1, tl::typelist_11(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12)>
 62     #define typelist_13(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13) typelist<t1, tl::typelist_12(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13)>
 63     #define typelist_14(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14) typelist<t1, tl::typelist_13(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14)>
 64     #define typelist_15(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15) typelist<t1, tl::typelist_14(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15)>
 65     #define typelist_16(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16) typelist<t1, tl::typelist_15(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16)>
 66     #define typelist_17(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17) typelist<t1, tl::typelist_16(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17)>
 67     #define typelist_18(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18) typelist<t1, tl::typelist_17(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18)>
 68     #define typelist_19(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19) typelist<t1, tl::typelist_18(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19)>
 69     #define typelist_20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20) typelist<t1, tl::typelist_19(t2, t3, t4, t5, t6, t7, t8, t9, t10, t11, t12, t13, t14, t15, t16, t17, t18, t19, t20)>
 70  
 71  
 72     //////////////////////////////////////////////////////////////////////////////
 73     // 以下定义typelist的编译期的操作函数(通过偏特化实现)
 74     /**
 75      * length: 取typelist的长度
 76      */
 77     template<class tlist> struct length;
 78     template<> struct length<nulltype>
 79     {
 80         enum { value = 0 };
 81     };
 82     template<class head, class tail> struct length<typelist<head, tail> >
 83     {
 84         enum { value = 1 + length<tail>::value };
 85     };
 86  
 87     /**
 88      * typeat, 取链表在i位置上的类型
 89      */
 90     template<class tlist, unsigned int i> struct typeat;
 91     template<class head, class tail> struct typeat<typelist<head, tail>, 0>
 92     {
 93         typedef head result;
 94     };
 95     template<class head, class tail, unsigned int i> struct typeat<typelist<head, tail>, i>
 96     {
 97         typedef typename typeat<tail, i-1>::result result;
 98     };
 99  
100     /**
101      * typeat, 取链表在i位置上的类型, i超出了返回, 则返回defaulttype
102      */
103     template<class tlist, unsigned int index, typename defaulttype = nulltype> struct typeatnonstrict
104     {
105         typedef defaulttype result;
106     };
107     template <class head, class tail, typename defaulttype> struct typeatnonstrict<typelist<head, tail>, 0, defaulttype>
108     {
109         typedef head result;
110     };
111     template <class head, class tail, unsigned int i, typename defaulttype> struct typeatnonstrict<typelist<head, tail>, i, defaulttype>
112     {
113         typedef typename typeatnonstrict<tail, i - 1, defaulttype>::result result;
114     };
115  
116     /**
117      * 取链表上类型为t的序号, 没有则返回-1
118      */
119     template<class tlist, class t> struct indexof;
120     template<class t> struct indexof<nulltype, t>
121     {
122         enum { value = -1 };
123     };
124     template<class tail, class t> struct indexof<typelist<t,tail>, t>
125     {
126         enum { value = 0 };
127     };
128     template<class head, class tail, class t> struct indexof<typelist<head, tail>, t>
129     {
130     private:
131         enum { temp = indexof<tail, t>::value };
132     public:
133         enum { value = temp == -1 ? -1 : 1 + temp };
134     };
135  
136     /**
137      * append, 添加到链表尾部
138      */
139     template<class tlist, class t> struct append;
140     template<> struct append<nulltype, nulltype>
141     {
142         typedef nulltype result;
143     };
144     template<class t> struct append<nulltype,t>
145     {
146         typedef typelist_1(t) result;
147     };
148     template<class head, class tail> struct append<nulltype, typelist<head, tail> >
149     {
150         typedef typelist<head, tail> result;
151     };
152     template<class head, class tail, class t> struct append<typelist<head, tail>, t>
153     {
154         typedef typelist<head, typename append<tail, t>::result> result;
155     };
156  
157     /**
158      * erase 删除
159      */
160     template<class tlist, class t> struct erase;
161     template<class t> struct erase<nulltype, t>
162     {
163         typedef nulltype result;
164     };
165     template<class t, class tail> struct erase<typelist<t, tail>, t>
166     {
167         typedef tail result;
168     };
169     template<class head, class tail, class t> struct erase<typelist<head, tail>, t>
170     {
171         typedef typelist<head, typename erase<tail, t>::result> result;
172     };
173  
174     /**
175      * eraseall 删除
176      */
177     template<class tlist, class t> struct eraseall;
178     template<class t> struct eraseall<nulltype, t>
179     {
180         typedef nulltype result;
181     };
182     template<class t, class tail> struct eraseall<typelist<t, tail>, t>
183     {
184         typedef typename eraseall<tail, t>::result result;
185     };
186     template<class head, class tail, class t> struct eraseall<typelist<head, tail>, t>
187     {
188         typedef typelist<head, typename eraseall<tail, t>::result> result;
189     };
190  
191     /**
192      * 生成typelist类型
193      */
194     template<class t1=nulltype,  class t2=nulltype,  class t3=nulltype,  class t4=nulltype,  class t5=nulltype,
195              class t6=nulltype,  class t7=nulltype,  class t8=nulltype,  class t9=nulltype,  class t10=nulltype,
196              class t11=nulltype, class t12=nulltype, class t13=nulltype, class t14=nulltype, class t15=nulltype,
197              class t16=nulltype, class t17=nulltype, class t18=nulltype, class t19=nulltype, class t20=nulltype>
198     struct tlmaker
199     {
200     private:
201         typedef typelist_20(t1, t2, t3, t4, t5, t6, t7, t8, t9, t10,
202                             t11, t12, t13, t14, t15, t16, t17, t18, t19, t20) tmplist;
203     public:
204         typedef typename eraseall<tmplist, nulltype>::result result;
205     };
206  
207     /////////////////////////////////////////////////////////////////////////////////////
208     //判断类型t是否可以转换成类型u(参考了wbl库, 直接采用loki, 编译时会有警告
209     //关键:如果能够转换, 则接收u的函数, 也能够接收t
210     template<class t, class u>
211     class conversion
212     {
213     protected:
214         typedef char yes;
215         struct no {char dummy[2];};
216         struct any_conversion
217         {
218             template <typename p> any_conversion(const volatile p&);
219             template <typename p> any_conversion(p&);
220         };
221  
222         template <typename p> struct conversion_checker
223         {
224             static no  _m_check(any_conversion ...);
225             static yes _m_check(p, int);
226         };    
227  
228         static t _m_from;
229     public:
230         enum
231         {
232             //是否可以转换(如果test(maket())匹配到了static small test(u), 则可以转换)
233             exists      = (sizeof(conversion_checker<u>::_m_check(_m_from, 0)) == sizeof(yes)),
234             //是否可以双向转换
235             exists2way  = exists && conversion<u, t>::exists,
236             //是否相同类型
237             sametype    = false
238         };
239     };
240  
241     //偏特化来确定sametype
242     template<class t>
243     class conversion<t, t>
244     {
245     public:
246         enum
247         {
248             exists      = true,
249             exists2way  = true,
250             sametype    = true
251         };
252     };
253  
254     //判断两个类是否可以继承
255     //关键:子类指针可以转换成父类指针, 且不是void*类型
256     //相同类型, supersubclass判断为true
257     #define supersubclass(t, u) (tl::conversion<const u*, const t*>::exists && !tl::conversion<const t*, const void*>::sametype)
258     //相同类型, supersubclass_strict判断为false
259     #define supersubclass_strict(t, u) (supersubclass(t, u) && !tl::conversion<const t, const u>::sametype)
260  
261     ///////////////////////////////////////////////////////////////////////////////////////////////
262     // 类型选择器
263     template<bool flag, typename u, typename v>
264     struct typeselect
265     {
266         typedef u result;
267     };
268  
269     template<typename u, typename v>
270     struct typeselect<false, u, v>
271     {
272         typedef v result;
273     };
274  
275     ///////////////////////////////////////////////////////////////////////////////////////
276     /**
277      * 类型萃取器, copy至loki库
278      */
279     template<typename t>
280     class typetraits
281     {
282     private:
283  
284         ///////////////////////////////////////////////////////
285         //提取引用的原始类型(即去掉引用类型)
286         template<class u>
287         struct referencetraits
288         {
289             enum { result = false };
290             typedef u result;
291         };
292  
293         template<class u>
294         struct referencetraits<u&>
295         {
296             enum { result = true };
297             typedef u result;
298         };
299  
300         ///////////////////////////////////////////////////////
301         //指针类型
302         template<class u>
303         struct pointertraits
304         {
305             enum { result = false };
306             typedef tl::nulltype result;
307         };
308  
309         template<class u>
310         struct pointertraits<u*>
311         {
312             enum { result = true };
313             typedef u result;
314         };
315  
316         template<class u>
317         struct pointertraits<u*&>
318         {
319             enum { result = true };
320             typedef u result;
321         };
322  
323         ///////////////////////////////////////////////////////
324         //成员函数指针, gcc下面支持有问题, 屏蔽之
325         template<typename u>
326         struct pointertomembertraits
327         {
328             enum { result = false };
329         };
330  
331         template<class u, class v>
332         struct pointertomembertraits<u v::*>
333         {
334             enum { result = true };
335         };
336  
337         template<class u, class v>
338         struct pointertomembertraits<u v::*&>
339         {
340             enum { result = true };
341         };
342  
343         ///////////////////////////////////////////////////////
344         // const
345         template<typename u>
346         struct unconsttraits
347         {
348             enum { result = false };
349             typedef u result;
350         };
351         template<typename u>
352         struct unconsttraits<const u>
353         {
354             enum { result = true };
355             typedef u result;
356         };
357         template<typename u>
358         struct unconsttraits<const u&>
359         {
360             enum { result = true };
361             typedef u& result;
362         };
363  
364         ///////////////////////////////////////////////////////
365         // volatile
366         template<typename u>
367         struct unvolatiletraits
368         {
369             enum { result = false };
370             typedef u result;
371         };
372         template<typename u>
373         struct unvolatiletraits<volatile u>
374         {
375             enum { result = true };
376             typedef u result;
377         };
378         template<typename u>
379         struct unvolatiletraits<volatile u&>
380         {
381             enum { result = true };
382             typedef u& result;
383         };
384     public:
385         //t是否是指针类型
386         enum { ispointer        = pointertraits<t>::result };
387         //t是否是引用类型
388         enum { isreference         = referencetraits<t>::result };
389         //t是否指向成员函数的指针
390         enum { ismemberpointer     = pointertomembertraits<t>::result };
391  
392         //t是否是const类型
393         enum { isconst          = unconsttraits<t>::result };
394         //t是否是volatile类型
395         enum { isvolatile       = unvolatiletraits<t>::result };
396  
397         //如果t是指针类型,则获取t的原类型, 即去掉指针类型
398         typedef typename pointertraits<t>::result             pointeetype;
399         //如果t是引用类型,则获取t的原类型, 即去掉引用类型
400         typedef typename referencetraits<t>::result         referencedtype;
401         //如果t是const类型,则获取t的原类型, 即去掉const类型
402         typedef typename unconsttraits<t>::result           nonconsttype;
403         //如果t是volatile类型,则获取t的原类型, 即去掉volatile类型
404         typedef typename unvolatiletraits<t>::result        nonvolatiletype;
405         //去掉const volatile类型
406         typedef typename unvolatiletraits<typename unconsttraits<t>::result>::result unqualifiedtype;
407  
408     public:
409  
410         //////////////////////////////////////////////////////
411         //
412         typedef tl::tlmaker<unsigned char, unsigned short, unsigned int, unsigned long, unsigned long long>::result unsignedints;
413         typedef tl::tlmaker<signed char, short, int, long, long long>::result signedints;
414         typedef tl::tlmaker<bool, char, wchar_t>::result otherints;
415         typedef tl::tlmaker<float, double, long double>::result floats;
416         typedef tl::typelist_2(tl::emptytype, tl::nulltype) nulltypes;
417  
418         //无符号整形
419         enum { isstdunsignedint = tl::indexof<unsignedints, t>::value >= 0 };
420         //有符号整形
421         enum { isstdsignedint     = tl::indexof<signedints, t>::value >= 0 };
422         //整形
423         enum { isstdint         = isstdunsignedint || isstdsignedint || tl::indexof<otherints, t>::value >= 0 };
424         //浮点类型
425         enum { isstdfloat         = tl::indexof<floats, t>::value >= 0 };
426         //数值类型
427         enum { isstdarith         = isstdint || isstdfloat };
428         //基础类型(包括void)
429         enum { isstdfundamental    = isstdarith || tl::indexof<tl::typelist_1(void), t>::value >= 0};
430         //空类型
431         enum { isnulltype       = tl::indexof<nulltypes, t>::value >= 0 };
432         //简单类型
433         enum { isbasetype       = isstdarith || ispointer || ismemberpointer };
434  
435         //对于复杂类型, 获取数据的引用类型, 即加上引用类型
436         typedef typename typeselect<isbasetype, t, referencedtype&>::result referencetype;
437  
438         //对于复杂类型且非空类型, 获取数据的引用类型, 即加上引用类型
439         //typedef typename typeselect<isbasetype || isnulltype, t, referencedtype&>::result referencetypeex;
440  
441         //获取数据的原类型, 消除引用的引用这种情况
442         typedef typename typeselect<!isreference, t, referencedtype&>::result parametertype;
443     };
444  
445     ////////////////////////////////////////////////////////////////////////////////////////////////////
446     //下面的使用开始展示typelist的威力, 用于自动生成class
447  
448     //散乱的继承体系
449     template<class tlist, template <class> class unit>
450     class scatterhierarchy;
451  
452     /*
453     namespace p
454     {
455         //注释copy至loki库
456         // the following type helps to overcome subtle flaw in the original
457         // implementation of genscatterhierarchy.
458         // the flaw is revealed when the input type list of genscatterhierarchy
459         // contains more then tars element of the same type (e.g. loki_typelist_2(int, int)).
460         // in this case genscatterhierarchy will contain multiple bases of the same
461         // type and some of them will not be reachable (per 10.3).
462         // for example before the fix the first element of tuple<loki_typelist_2(int, int)>
463         // is not reachable in any way!
464         template<class, class>
465         struct scatterhierarchytag;
466     }
467     template<class t1, class t2, template <class> class unit>
468     class scatterhierarchy<typelist<t1, t2>, unit> : public scatterhierarchy<p::scatterhierarchytag<t1, t2>, unit>
469                                                    , public scatterhierarchy<t2, unit>
470     {
471     public:
472         typedef typelist<t1, t2> tlist;
473         typedef scatterhierarchy<p::scatterhierarchytag<t1, t2>, unit> leftbase;
474         typedef scatterhierarchy<t2, unit> rightbase;
475         template<typename t> struct rebind
476         {
477             typedef unit<t> result;
478         };
479     };
480     // in the middle *unique* class that resolve possible ambiguity
481     template <class t1, class t2, template <class> class unit>
482     class scatterhierarchy<p::scatterhierarchytag<t1, t2>, unit>
483         : public scatterhierarchy<t1, unit>
484     {
485     };
486     */
487  
488     //具现化继承体系
489     template <class t1, class t2, template <class> class unit>
490     class scatterhierarchy<typelist<t1, t2>, unit>
491         : public scatterhierarchy<t1, unit>
492         , public scatterhierarchy<t2, unit>
493     {
494     public:
495         typedef typelist<t1, t2> tlist;
496         typedef scatterhierarchy<t1, unit> leftbase;
497         typedef scatterhierarchy<t2, unit> rightbase;
498         template <typename t> struct rebind
499         {
500             typedef unit<t> result;
501         };
502     };
503  
504     template<class atomictype, template <class> class unit>
505     class scatterhierarchy : public unit<atomictype>
506     {
507     public:
508         typedef unit<atomictype> leftbase;
509  
510         template<typename t> struct rebind
511         {
512             typedef unit<t> result;
513         };
514     };
515  
516     template<template <class> class unit>
517     class scatterhierarchy<nulltype, unit>
518     {
519     public:
520         template<typename t> struct rebind
521         {
522             typedef unit<t> result;
523         };
524     };
525  
526     /////////////////////////////////////////////////////////////////////
527     //构建继承体系后, 采用下面的函数获取继承体系中某个类
528  
529     template<class t, class h>
530     struct fieldhelperbytype
531     {
532         typedef typename h::template rebind<t>::result resulttype;
533         static resulttype& dochange(h &obj)
534         {
535             return static_cast<resulttype&>(obj);
536         }
537     };
538     template<class t, class h>
539     struct fieldhelperbytype<t, const h>
540     {
541         typedef const typename h::template rebind<t>::result resulttype;
542         static resulttype& dochange(const h &obj)
543         {
544             return (resulttype&)obj;
545         }
546     };
547  
548     //直接按照类型获取, 如果有两个相同的类型, 则编译不过
549     template<class t, class h>
550     typename fieldhelperbytype<t, h>::resulttype& field(h &obj)
551     {
552         return fieldhelperbytype<t, h>::dochange(obj);
553     }
554  
555     /////////////////////////////////////////////////////////////////////
556     // 根据索引获取字段
557     //定义tuple, 默认的数据操作器(unit)
558     template<typename t>
559     struct tupleunit
560     {
561         t _value;
562         operator t&()               { return _value; }
563         operator const t&() const   { return _value; }
564     };
565  
566     template<class tlist>
567     struct tuple : public scatterhierarchy<tlist, tupleunit>
568     {
569     };
570  
571     //定义fieldhelperbyindex
572     template<class h, unsigned int i> struct fieldhelperbyindex;
573  
574     //特化版本的fieldhelperbyindex, 推导出最后一个元素
575     template<class h>
576     struct fieldhelperbyindex<h, 0>
577     {
578         typedef typename h::tlist::h elementtype;
579         typedef typename h::template rebind<elementtype>::result unittype;
580  
581         enum
582         {
583             istuple = conversion<unittype, tupleunit<elementtype> >::sametype,
584             isconst = typetraits<h>::isconst
585         };
586  
587         typedef const typename h::leftbase constleftbase;
588         typedef typename typeselect<isconst, constleftbase, typename h::leftbase>::result leftbase;
589         typedef typename typeselect<istuple, elementtype, unittype>::result unqualifiedresulttype;
590         typedef typename typeselect<isconst, const unqualifiedresulttype, unqualifiedresulttype>::result resulttype;
591  
592         static resulttype &dochange(h& obj)
593         {
594             leftbase &leftbase = obj;
595             return (resulttype&)leftbase;
596         }
597     };
598  
599     //根据索引获取fieldhelper
600     template<class h, unsigned int i>
601     struct fieldhelperbyindex
602     {
603         typedef typename typeat<typename h::tlist, i>::result elementtype;
604         typedef typename h::template rebind<elementtype>::result unittype;
605  
606         enum
607         {
608             istuple = conversion<unittype, tupleunit<elementtype> >::sametype,
609             isconst = typetraits<h>::isconst
610         };
611  
612         typedef const typename h::rightbase constrightbase;
613         typedef typename typeselect<isconst, constrightbase, typename h::rightbase>::result rightbase;
614         typedef typename typeselect<istuple, elementtype, unittype>::result unqualifiedresulttype;
615         typedef typename typeselect<isconst, const unqualifiedresulttype, unqualifiedresulttype>::result resulttype;
616  
617         static resulttype &dochange(h& obj)
618         {
619             rightbase &rightbase = obj;
620             return fieldhelperbyindex<rightbase, i-1>::dochange(rightbase);
621         }
622     };
623  
624     //定义按照索引获取
625     template<unsigned int i, class h>
626     typename fieldhelperbyindex<h, i>::resulttype &field(h& obj)
627     {
628         return fieldhelperbyindex<h, i>::dochange(obj);
629     }
630 }
631  
632 }
633 #endif
634  

       是不是有一种看天书的感觉, 确实如此。

       也行, 姑且把它当成和stl类似的基础库, 别纠结于它。

 

转自:https://blog.csdn.net/stpeace/article/details/79772562

如对本文有疑问,请在下面进行留言讨论,广大热心网友会与你互动!! 点击进行留言回复

相关文章:

验证码:
移动技术网