c++ Factor泛型编程示例
c++ Factor泛型编程示例
c++ 泛型编程 之Factor (c++ 设计新思维)
一.概述
泛化仿函数是将“请求(函数)封装起来”,存储与对象中,该对象是具有“value语义”的,因此支持拷贝,赋值和作为函数参数来传值(pass by value)。通过该对象可间接的处理封装的请求,类似于boost 中的function功能。本实现采用的是《Modern C++ Design》中的方案。更详尽的说,具有以下特点:
1. 可封装任何处理请求,可接受函数指针,成员函数指针,仿函数,甚至其它泛化仿函数。
2. 具备型别安全性,不会将错误的型别匹配到错误的函数上。
3. 一种带有“value语义的对象”。
先介绍下C++中的可调用体:
1. C风格的函数(C like function): void fun();
2. C风格的函数指针(C like pointto function): void (*pFun)();
3. 函数引用(reference to function),其行为本质上和const pointer to function类似。
4. 仿函数(functor),类中自定义了operator () 的对象。
5. Operator.*和operator->*的施行结果
6. 构造函数
在上述的任一项,可以在右侧添加一对圆括号(),在里头放入一组合适的参数。
先来讨论这样一个问题,既然想把函数请求封装到对象中,函数的参数如何确定?这里使用typelist(这是一个型别集,包含型别列表)。这里就可以把typelist作为HTFunctor的一个模板参数,包含所要封装函数的参数型别信息。下面就先介绍下typelist实作。
二.HTTypeList
[cpp]
1. template <class T, class U>
2. struct HTTypeList
3. {
4. typedef T Head;
5. typedef U Tail;
6. };
这是typelist的基本实作(只需两个类型),现在问题是如何把n个类型连成链表。看下面这个例子就明白了
1. typedef HTTypeList<char, HTTypeList<int, int> >
(利用模板参数推导,编译器自动产生,而不是运行期哦),这样两个以上的参数都解决了。
现在问题如何定义一个参数的typelist。方法是,第二个模板参数设为NullType(空类型),这样每个typelist都以NullType结尾,相当于C字符串的\0功能。看NullType的实作:
[cpp]
1. class HTNullType {};
接着就要生产typelist了(一个参数,两个参数,三个参数……)。这里用到宏,暂且定义4个typelist。
[cpp]
1. #define TYPELIST_1(T1) UTIL::HTTypeList<T1, UTIL::HTNullType>
2. #define TYPELIST_2(T1, T2) UTIL::HTTypeList<T1, TYPELIST_1(T2) >
3. #define TYPELIST_3(T1, T2, T3) UTIL::HTTypeList<T1, TYPELIST_2(T2, T3) >
4. #define TYPELIST_4(T1, T2, T3, T4) UTIL::HTTypeList<T1, TYPELIST_3(T2, T3, T4) >
另外要解决的问题,函数参数该是值类型(内部内型),还是引用类型(对于对象)。选择合适的类型显然能提高程序速度,肯定不想传递大对象参数时要额外拷贝。接下来这个东西就要登场了——( HTTypeTraits )
三:HTTypeTraits
可用于“编译期根据型别作判断”的泛型技术。大家也可参看boost中的type traits。
[cpp]
1. // 判断T及U是否标示同一个类型
2. template <typename T, typename U>
3. struct HTIsSameType
4. {
5. private:
6. template<typename>
7. struct In
8. { enum { value = false }; };
9.
10. template<>
11. struct In<T>
12. { enum { value = true }; };
13.
14. public:
15. enum { value = In<U>::value };
16. };
[cpp]
1. // 依flag选择两个类型中的一个,true为T,false为U
2. template <bool flag, typename T, typename U>
3. struct HTSelect
4. {
5. private:
6. template<bool>
7. struct In
8. { typedef T Result; };
9.
10. template<>
11. struct In<false>
12. { typedef U Result; };
13.
14. public:
15. typedef typename In<flag>::Result Result;
16. };
[cpp]
1. // 编译期bool型
2. typedef char HTYes;
3. struct HTNo { char padding[8]; };
4.
5. // 型别映射为型别,用于模板函数的偏特化,C++标准模板函数不能偏特化
6. template <typename T>
7. struct HTType2Type { typedef T Type; };
8.
9. // 判断T是否为类
10. template <typename T>
11. struct HTIsClass
12. {
13. // U为类的话,会具现化此重载函数,因为参数为函数指针,即指向成员的函数指针
14. template <typename U> static HTYes IsClassTest(void(U::*)(void));
15. // U为非类,会具现化此重载函数
16. // C++标准:只有当其它所有的重载版本都不能匹配时,具有任意参数列表的重载版本才会被匹配
17. template <typename U> static HTNo IsClassTest(...);
18.
19. // 对于sizeof,表达式不会被真正求值,编译器只推导出表达式的返回结果的型别,因此只需函数的声明即可
20. static const bool value = sizeof(IsClassTest<T>(0)) = sizeof(HTYes);
21. };
22.
23. // 判断T是否为引用类型
24. template <typename T>
25. struct HTIsReference
26. {
27. template <typename U> static HTYes IsReference(HTType2Type<U&>);
28. template <typename U> static HTNo IsReference(...);
29.
30. static const bool value= sizeof(IsReference(HTType2Type<T>())) == sizeof(HTYes);
31. };
32.
33. template <typename T>
34. class HTTypeTraits
35. {
36.
37. public:
38. enum {
39. isVoid =
40. HTIsSameType<T, void>::value ||
41. HTIsSameType<T, const void>::value ||
42. HTIsSameType<T, volatile void>::value ||
43. HTIsSameType<T, const volatile void>::value
44. };
45.
46. enum { isReference = HTIsReference<T>::value };
47.
48. private:
49. template<bool IsRef>
50. struct AdjReference
51. {
52. template<typename U>
53. struct In { typedef U const & Result; };
54. };
55.
56. template<>
57. struct AdjReference<true>
58. {
59. template<typename U>
60. struct In { typedef U Result; };
61. };
62.
63. typedef typename AdjReference<isReference || isVoid>::
64. template In<T>::Result AdjType;
65.
66. // 正确的选择函数参数的类型
67. // 对于精巧型(有构造函数和析构函数额外调用)采用引用传参数,对于纯量型(数值型别,枚举型别,指针,指向成员的指针)采用直接传值
68. typedef typename HTSelect<HTIsClass<T>::value, AdjType, T>::Result ParmType;
69. };
四:HTFunctor
HTTypeList及HTTypeTraits提供我们强大的功能。这让我们实作HTFunctor更加的方便。下面直接看代码。
[cpp]
1. // Functor对象明显是个小对象,这里采用小对象分配器
2. // 使用了Command模式及IMPL模式
3. template <typename R>
4. struct HTFunctorImplBase : public HTSmallObject<>
5. {
6. typedef R ResultType;
7. typedef HTEmptyType Parm1;
8. typedef HTEmptyType Parm2;
9. };
10.
11. template <typename R, class TList, class ObjClass>
12. struct HTFunctorImpl;
13.
14. // 无参数版本
15. template <typename R, class ObjClass>
16. struct HTFunctorImpl<R, HTNullType, ObjClass> : public HTFunctorImplBase<R>
17. {
18. typedef R ResultType;
19.
20. virtual ResultType operator()(ObjClass* pObj) = 0;
21. virtual HTFunctorImpl* Clone() const = 0;
22. virtual ~HTFunctorImpl() {}
23. };
24.
25. // 一个参数版本
26. template <typename R, typename P1, class ObjClass>
27. struct HTFunctorImpl<R, TYPELIST_1(P1), ObjClass> : public HTFunctorImplBase<R>
28. {
29. typedef R ResultType;
30. typedef typename HTTypeTraits<P1>::ParmType Parm1;
31.
32. virtual ResultType operator()(Parm1, ObjClass* pObj) = 0;
33. virtual HTFunctorImpl* Clone() const = 0;
34. virtual ~HTFunctorImpl() {}
35. };
36.
37. // 两个参数版本
38. template <typename R, typename P1, typename P2, class ObjClass>
39. struct HTFunctorImpl<R, TYPELIST_2(P1, P2), ObjClass> : public HTFunctorImplBase<R>
40. {
41. typedef R ResultType;
42. typedef typename HTTypeTraits<P1>::ParmType Parm1;
43. typedef typename HTTypeTraits<P2>::ParmType Parm2;
44.
45. virtual ResultType operator()(Parm1, Parm2, ObjClass* pObj) = 0;
46. virtual HTFunctorImpl* Clone() const = 0;
47. virtual ~HTFunctorImpl() {}
48. };
49.
50. // 可调用体(即封装的处理函数)为仿函数
51. template <class ParentFunctor, typename Fun, class ObjClass>
52. class HTFunctorHandler :
53. public HTFunctorImpl
54. <
55. typename ParentFunctor::ResultType,
56. typename ParentFunctor::ParmList,
57. ObjClass
58. >
59. {
60. typedef typename ParentFunctor::Impl Base;
61. public:
62. typedef typename Base::ResultType ResultType;
63.
64. typedef typename Base::Parm1 Parm1;
65. typedef typename Base::Parm1 Parm2;
66.
67. HTFunctorHandler(const Fun& fun) : m_fun(fun) {}
68. HTFunctorHandler* Clone() const { return new HTFunctorHandler(*this); }
69.
70. ResultType operator()(ObjClass* pObj)
71. { return m_fun(); }
72.
73. ResultType operator()(Parm1 p1, ObjClass* pObj)
74. { return m_fun(p1); }
75.
76. ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj)
77. { return m_fun(p1, p2); }
78.
79. private:
80. Fun m_fun;
81. };
82.
83. // 可调用体(即封装的处理函数)为类成员函数,调用需传递对象指针
84. template <class ParentFunctor, typename Fun, class ObjClass>
85. class HTMemFunHandler :
86. public HTFunctorImpl
87. <
88. typename ParentFunctor::ResultType,
89. typename ParentFunctor::ParmList,
90. ObjClass
91. >
92. {
93. typedef typename ParentFunctor::Impl Base;
94. public:
95. typedef typename Base::ResultType ResultType;
96.
97. typedef typename Base::Parm1 Parm1;
98. typedef typename Base::Parm1 Parm2;
99.
100. HTMemFunHandler(const Fun& fun) : m_fun(fun) {}
101. HTMemFunHandler* Clone() const { return new HTMemFunHandler(*this); }
102.
103. ResultType operator()(ObjClass* pObj)
104. { return (pObj->*m_fun)(); }
105.
106. ResultType operator()(Parm1 p1, ObjClass* pObj)
107. { return (pObj->*m_fun)(p1); }
108.
109. ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj)
110. { return (pObj->*m_fun)(p1, p2); }
111.
112. private:
113. Fun m_fun;
114. };
115.
116. // HTFunctor实现体
117. template <typename R, class TList = YKNullType, class ObjClass = YKEmptyType>
118. class HTFunctor
119. {
120. typedef HTFunctorImpl<R, TList, ObjClass> Impl;
121. public:
122. typedef R ResultType;
123. typedef TList ParmList;
124. typedef typename Impl::Parm1 Parm1;
125. typedef typename Impl::Parm2 Parm2;
126.
127. HTFunctor() : m_spImpl() {}
128. HTFunctor(const HTFunctor& rhs) : m_spImpl(rhs.m_spImpl->Clone()) {}
129. explicit HTFunctor(std::auto_ptr<Impl> spImpl) : m_spImpl(spImpl) {}
130.
131. HTFunctor& operator=(const HTFunctor& rhs)
132. {
133. HTFunctor copy(rhs);
134. Impl* p = m_spImpl.release();
135. m_spImpl.reset(copy.m_spImpl.release());
136. copy.m_spImpl.reset(p);
137. return *this;
138. }
139.
140. template <typename Fun>
141. HTFunctor(Fun fun)
142. : m_spImpl(new
143. HTSelect<
144. HTIsSameType<ObjClass, HTEmptyType>::value,
145. HTFunctorHandler<HTFunctor, Fun, ObjClass>,
146. HTMemFunHandler<HTFunctor, Fun, ObjClass> >::Result(fun))
147. {}
148.
149. ResultType operator()(ObjClass* pObj = HT_NULL) {
150. return (*m_spImpl)(pObj);
151. }
152.
153. ResultType operator()(Parm1 p1, ObjClass* pObj = HT_NULL) {
154. return (*m_spImpl)(p1, pObj);
155. }
156.
157. ResultType operator()(Parm1 p1, Parm2 p2, ObjClass* pObj = HT_NULL) {
158. return (*m_spImpl)(p1, p2, pObj);
159. }
160.
161. private:
162. std::auto_ptr<Impl> m_spImpl;
163. };
五.Krypton Factor C++
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
using namespace std;
int cnt;
int n,L;
int ans;
int S[100001];
int dfs(int cur)
{
if(cnt++==n){
for(int i=0;i<cur;i++){if(i%4==0&&i&&i<cur&&i%64!=0)cout<<" ";if(i&&i%64==0&&i<cur)cout<<endl;printf("%c",'A'+S[i]);ans++;}
printf("\n");
return 0;
}
for(int i=0;i<L;i++)
{
S[cur]=i;
int ok=1;
for(int j=1;j*2<=cur+1;j++)
{
int equal_=1;
for(int k=0;k<j;k++)
if(S[cur-k]!=S[cur-k-j]){equal_=0;break;}
if(equal_){ok=0;break;}
}
if(ok)if(!dfs(cur+1))return 0;
}
return 1;
}
int main()
{
while(cin>>n>>L&&n&&L){
ans=0;
cnt=0;
dfs(0);
cout<<ans<<endl;
}
return 0;
}
六.C++泛型编程与设计模式( 函数内部类 )
class Interface {
virtual void func() =0;
};
template<class T, class P>
Interface *makeAdapter(T tt, P pp) {
int a = 10;
static int count = 10;
class Local : public Interface {
public:
Local(const T &t, const P &p) : p(p), t(t) {
// cout << a << endl;
cout << count << endl;
}
virtual void func() {
}
private:
P p;
T t;
static int k;
};
return new Local(tt,pp);
};
这个例子很简单,开始定义了一个接口,然后定义了一个方法,该方法返回一个Interface的指针,在makeAdapter方法中,定义了Local类,然后继承自接口Interface,因为这里的Local是个类,是个局部的,所以无法被外部代码所使用,这就说明了,局部类的使用限制性还是挺大的:
1. 要么就在方法内部使用。
2. 如果要在外部使用,不论是直接返回,还是存在其它的包裹方式,都必须继承已经存在的接口或者是基类。
局部类这种独特的特性,非常类似于其他语言中的final类,如说PHP,JAVA,因为他是局部的,所以无法被外部继承。如果不希望类被继承的话,局部类是个不错的方法。
参考链接:
https://blog.csdn.net/zhuyingqingfen/article/details/10124527
https://blog.csdn.net/Zero_979/article/details/81205702
https://blog.csdn.net/oKanJianLiao/article/details/80711167