std:函数和函数指针的简单实现。
凡是敢在简历上写“精通C”或“精通C”的人,都被面试官问死了.
今天没事干,想着怎么实现std:function功能,反正呆着也没意思。
首先使用它:
1 my functionint(const STD :3360 string)fc=test _ func;
2 int len=fc(' as dasd ');
实现后,暂时的目标是让这两句话成功运行。其中myfunction是实现类似std:函数的类名;Test_func是一个函数指针,其参数类型为const string,返回值为intFc是一个变量名,我想用它来进行函数调用。
显然,myfunction类是一个只有一个模板参数的模板类,所以您可以先这样做:
1模板类型名T
2类函数
3 {
4 };
下一步是什么.
看看第二行代码:
int len=fc(' as dasd ');
这句话包含了很多信息:
1.因为fc是myfunction类的实例化对象,它执行类似obj(xxx)的操作,所以需要重载operator()的运算符。
2.根据1,在运算符()的重载中,类型字符串的参数是必需的,即test_func函数的参数。换句话说,你需要知道myfunction参数的类型,然后才能通用。
3.同样,您需要知道test_func函数返回值的类型;
综上所述,接下来的——。
1 templatetypename TRet,typename TArg1
2级myfunctionTRet(TArg1)
3 {
4公众号:
5 myfunction() {}
6 ~myfunction() {}
七
8 public:
9 TRet运算符()(TArg1 arg1)
10 {
11 }
12
13 TRet(*)(TArg1)运算符=(TRet(*)(TArg1) fc)
14 {
15 }
16
17 };
类myfunctionTRet(TArg1)使用模板专门化。这种写法不常见,尤其是里面的模板参数。
当然,上面代码中的函数指针不能这样写,比如形式参数fc需要更改,任何人都可以这样写。
1 templatetypename TRet,typename TArg1
2级myfunctionTRet(TArg1)
3 {
4公众号:
5 myfunction() {}
6 ~myfunction() {}
七
8 public:
9 TRet运算符()(TArg1 arg1)
10 {
11 }
12
13 TRet(*)(TArg1)运算符=(TRet(*fc)(TArg1))
14 {
15 }
16
17 };
当我们填入真正可用的指针和两个运算符重载函数时,代码就差不多完成了。
1 templatetypename TRet,typename TArg1
2级myfunctionTRet(TArg1)
3 {
4公众号:
5 myfunction() : _fc(NULL) {}
6 ~myfunction() {}
七
8 myfunction(TRet(*fc)(TArg1))
9 : _fc(fc)
10 {
11 }
12
13 public:
14 TRet运算符()(TArg1 arg1)
15 {
16 if (_fc==NULL)
17 {
18掷(STD : logic _ error(' The _ fc为nullptr!'));
19返回TRet();
20 }
21
22 return _ fc(arg 1);
23 }
24
25 TRet(*)(TArg1)运算符=(TRet(*fc)(TArg1))
26 {
27 _ fc=fc
28 return _ fc
29 }
30
31列兵:
32 TRet(* _ fc)(targ 1);
33 };
正在我高兴之余,我试着编译了一下……未通过!错在了第25行 :TRet(*)(TArg1) operator=(TRet(*fc)(TArg1))。也就是说,返回函数指针还不能这样写。
于是我转变了一下写法,把返回值类型typedef一下:
1 typedef TRet(*TFunc)(TArg1); 2 TFunc operator=(TRet(*fc)(TArg1)) 3 { 4 _fc = fc; 5 return _fc; 6 }
这样就可以了。
。
。
。
但是我从小就头铁,我就想知道,如果不用typedef该怎么办
试了好久都没成功,直到我看见了这个:
TRet(*fc)(TArg1)
也就是说,函数指针的定义法就不能按照普通的 type name; 的形式,应当是:
type_ret(*name)(type_arg)
这样的。所以,我把operator=函数改成了这样:
TRet(*operator=(TRet(*fc)(TArg1)))(TArg1)
实际上,就是把operator=(TRet(*fc)(TArg1))这个没有返回值的函数体扔在了前面的星号后。
不就是递归吗我也会。
至此,整个类也就完成了,如下:
#include iostream #include string int test_func(const std::string a) { return a.size(); } templatetypename T class myfunction { }; templatetypename TRet, typename TArg1 class myfunctionTRet(TArg1) { public: myfunction() : _fc(NULL) {} ~myfunction() {} myfunction(TRet(*fc)(TArg1)) : _fc(fc) { } public: TRet operator()(TArg1 arg1) { if (_fc == NULL) { throw(std::logic_error("The _fc is nullptr!")); return TRet(); } return _fc(arg1); } TRet(*operator=(TRet(*fc)(TArg1)))(TArg1) { _fc = fc; return _fc; } private: TRet(*_fc)(TArg1); }; int main() { int (*fc)(const std::string) = test_func; size_t len = fc("asd"); myfunctionint(const std::string) fc2 = test_func; int len2 = fc2("asdasd"); std::cout len2 std::endl; return 0; }
因为不使用c++11的语法,也就是不能使用可变参数模板,此类只能用于一个参数的函数。如果两个的该怎么办
那就再特化一遍:
1 templatetypename TRet, typename TArg1, typename TArg2 2 class myfunctionTRet(TArg1, TArg2) 3 { 4 public: 5 myfunction() : _fc(NULL) {} 6 ~myfunction() {} 7 8 myfunction(TRet(*fc)(TArg1, TArg2)) 9 : _fc(fc) 10 { 11 } 12 13 public: 14 TRet operator()(TArg1 arg1, TArg2 arg2) 15 { 16 if (_fc == NULL) 17 { 18 throw(std::logic_error("The _fc is nullptr!")); 19 return TRet(); 20 } 21 22 return _fc(arg1, arg2); 23 } 24 25 TRet(*operator=(TRet(*fc)(TArg1, TArg2)))(TArg1, TArg2) 26 { 27 _fc = fc; 28 return _fc; 29 } 30 31 private: 32 TRet(*_fc)(TArg1, TArg2); 33 };
为了兼容更多参数的函数,你可能要特化好多遍这个代码。当没有语法支持时,好多人都这么干。
内容来源网络,如有侵权,联系删除,本文地址:https://www.230890.com/zhan/51641.html