1 . 通用函数可变参数模板
对于有些时候,我们无法确切的知道,函数的参数个数时,而又不想过多的使用所谓的函数重载,那么就可以效仿下面的例子:
1 #include<iostream>
2 #include<Array>
3 void showall() { return; }
4
5 template <typename R1 ,typename... Args>
6
7 void showall(R1 var, Args...args) {
8
9 std::cout << var << std::endl;
10 showall(args...);
11 }
12
13 int main(int argc, char * args[]) {
14
15
16 showall(1, 2, 3, 4, 5);
17 showall("gxjun","dadw","dasds");
18 showall(1.0,2.0,3.5);
19 std::cin.get();
20 return 0;
21 }
在游戏开发中,时常会用到这样的模板,类型不确定,参数的个数不确定,所以需要用一种类似于递归的函数来处理。 第一个函数,表示的是在参数为0时,结束。
效果:
2. 如何使用仿函数:
首先仿函数的定义: ,仿函数也叫函数对象(Function Object, or Functor),定义就是任何可以像函数一样被调用的对象。一个普通的函数是函数对象,一个函数指针当然也是,广义上说任何定义了operator()的类对象都可以看作是函数对象。 (找到文档)
其实,往直白的地方说,就是一个不是函数但是具有函数功能且用法和函数相同的对象(结构体或者类)。
下面举个栗子(用结构体实现函数功能):
1 /*关于C++仿函数*/
2 #include<iostream>
3 #include<functional>
4 using namespace std;
5 using namespace std::placeholders;
6
7 template <typename R1 , typename R2>
8 struct Calc
9 {
10 void add(R1 a) {
11 cout << a << endl;
12 };
13 void add_1(R1 a, R1 b) {
14 cout << a + b << endl;
15 }
16 };
17
18 int main(int argc, char * args[]) {
19
20 //函数指针
21 void(Calc<int, double>::*fc)(int a) = &Calc<int, double >::add;
22 // fc(25);
23 //显然上面的式子比较的麻烦
24
25 Calc < int, int> calc;
26 auto fun = bind(&Calc<int, int >::add, &calc, _1);
27 auto fun_2 = bind(&Calc<int, int >::add_1, &calc, _1,_2);
28 fun(123);
29 fun_2(12,24);
30 cin.get();
31 return 0;
32 }
对于bind()这个函数,开头的是地址,函数名,后面的是第一个列子中的Args....不定参数类型、
效果图为:
3. 使用using别名,函数指针,typdef来实现函数的调用
虽然是寥寥的几行代码,但是功能在实际应用中,却会发挥很大的作用。
1 //using别名使用用法
2 #include<iostream>
3 #include<windows.h>
4 int calc() {
5 //当为无参数时,返回0值
6 return 0;
7 }
8
9 template <typename R1 ,typename...Args>
10 int calc(R1 a, Args...args) {
11
12 return a + calc(args...);
13 }
14
15 int main(int argc , char * args []) {
16
17 //使用函数指针
18 int(*fun) (int ,int ,int ,int ) = calc;
19 system("echo 使用函数指针实现1~4累加");
20 std::cout << fun(1,2,3,4)<<std::endl;
21 //使用typedef来实现该功能
22 system("echo 使用typedef实现1~4累加");
23 typedef int(*Add)(int, int, int);
24 Add Gadd = calc;
25 std::cout << Gadd(1, 2, 3) << std::endl;
26 //使用using别名来实现这么个功能
27 system("echo 使用using实现1~4累加");
28 using Func = int(*) (int, int, int, int);
29 Func func = calc;
30 std::cout << func(1, 2, 3, 4) << std::endl;
31 std::cin.get();
32 return 0;
33 }
效果图:
4. C++模板元编程:
对于模板元编程: 我的理解是,你所要的计算,在编译的时候,已经处理玩了,只需要在运行的时候输出结果即可!
当我们每每学到模板元编程的时候,就会有一个混淆的词汇出现,哒,看------函数式编程。 到底什么是函数式编程呢?
建议去看这篇文章,http://www.ruanyifeng.com/blog/2012/04/functional_programming.html 模板元编程用处广泛,
我们知道当硬件条件限制的情况下,除了优化算法,还有一种途径,那就是用模板元编程。 现在就让我们来看看这个金典的应用吧!
斐波那契数列的计算......
1 #include<iostream>
2 #include<time.h>
3 #include<windows.h>
4 /*
5 斐波那契数列
6 H(1)=H(0)=1;
7 H(N)= H(N-1)+H(N-2);
8 */
9 using namespace std;
10
11 /* 普通版普通版 */
12 using _int = long ; //使用别名
13
14 _int feibona(_int ac) {
15 if (ac == 0||ac==1) return 1;
16 return feibona(ac-1) +feibona(ac-2);
17 }
18
19 /* 使用元编程 完全特化版 方法如下*/
20 template <_int N>
21 struct data {
22 //采用枚举
23 enum { res = data<N - 1>::res + data<N - 2>::res };
24 };
25
26 template <>
27 struct data<1> {
28 //采用枚举
29 enum { res = 1L };
30 };
31
32 template <>
33 struct data<0> {
34 //采用枚举
35 enum { res = 1L };
36 };
37
38
39 int main(int argc, char * args[]) {
40
41 time_t a ,b;
42 a = clock(); //开始记录时间
43 cout << data<45L>::res << endl;
44 b = clock(); //开始记录时间
45 system("echo 采用元编程所消耗的时间");
46 cout << (double)(b - a) / CLK_TCK<<"ms"<<endl;
47 a = clock();
48 cout << feibona(45L) << endl;
49 b = clock();
50 system("echo 采用普通的算法所消耗的时间");
51 cout << (double)(b - a) / CLK_TCK << "ms" << endl;
52 cin.get();
53 return 0;
54 }
两者相对比的效果图:
5 C++智能指针 ,关于智能指针和普通指针,的几种行为的对比
1 /*
2 智能指针:
3 对于C++而言: std::auto_ptr<double> ptr(new double);
4 对于C++11新的智能指针: std::unique_ptr<double> ps(new double);
5 通过下面几组数据做些一点
6 */
7 #include<iostream>
8 #include<memory>
9 #include<windows.h>
10 using namespace std;
11 /*模式一 分配内存地址,而不手动进行回收 */
12 void showp() {
13 system("echo 分配内存地址,而不手动进行回收");
14 for (int i = 0; i < 10000000; i++) {
15 double * p = new double; //不释放
16 }
17 cin.get();
18 }
19 /* 模式二,分配地址,并手动进行回收地址 */
20 void showp1() {
21 system("echo 分配地址,并手动进行回收地址");
22 for (int i = 0; i < 10000000; i++) {
23 double * p = new double; //不释放
24 delete p;
25 }
26 cin.get();
27
28 }
29 /*模式三,分配地址,采用c++通用指针*/
30 void showp2() {
31 system("echo 分配地址,采用c++通用指针");
32
33 for (int i = 0; i < 10000000; i++) {
34 double * p = new double; //不释放
35 auto_ptr<double> ps(p); //采用智能指针,不会多释放地址,旧版本vc98支持
36 }
37 cin.get();
38 }
39 /* 模式四,分配地址,采用C++11新型指针 */
40
41 void showp3() {
42
43 system("echo 分配地址,采用C++11新型指针");
44 for (int i = 0; i < 10000000; i++) {
45 auto_ptr<double> ps(new double); //采用智能指针,C++11新特性
46 }
47 cin.get();
48 }
49
50 int main(int argc , char * args []) {
51
52 //auto_ptr
53 //函数指针
54 void(*p[])() = { showp,showp1,showp2,showp3 };
55 //for (auto data : p) {
56 // data();
57 //}
58 p[1]();
59 system("echo 按一下结束");
60 cin.get();
61 return 0;
62 }
模式一: 消耗内存截图
模式二 吃掉的内存截图:
模式三,吃掉的内存截图:
模式四,吃掉的内存截图:
使用智能指针的好处:
1 、 不会对一个分配的地址,释放两次。如果手动释放地址,存在着重复释放或者漏放的情况。 避免内存泄露。
2. 释放及时,不会捣鼓电脑中cpu换句话说,不会吃cpu。而是电脑运缓慢....