抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

前期回顾

$$
程序 = 算法 + 数据结构
$$

数据结构: 能够存储任意类型

算 法: 能够操作存储任意类型数据的数据结构

泛型编程

泛型编程
面向过程编程 用 模板 实现函数过程
面向对象编程 用 模板 实现类

抽象化:

  • 面向过程
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

#include <iostream>
using namespace std;

// 将参数从问题中抽象话出来
int f(int x) {
return x * 2 + 1;
}

// 什么叫抽象化
int main() {
// 问x * 2 + 1 等于多少

// x = 1; 这个叫具体话
cout << 1 * 2 + 1;

cout << f(1);
cout << f(2);
cout << f(3);
cout << f(4);

return 0;
}

模板 将【任意类型】从程序设计中抽象出来

模板

模板函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/*************************************************************************
> File Name: 1.template.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月22日 星期五 20时47分36秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x{
#define ENDS(x) } // end of namespace x

BEGINS(test1)

// typename 只是说明 T 是一个类型
// 这里typename T 还可以写成 class T 作用是一模一样的(未来可能会有 区别)
// template<class T>
template<typename T>

T add(T a, T b) {
return a + b;
}
/*
编译器自动生成 当编译调用的时候调用的不是模板方法而是编译器自动实例化的出来这个代码
所有说: 模板类可以使用虚函数,模板函数不能是虚函数
int add(int a, int b) {
ret urn a + b;
}

int main() {
/*
模板函数是怎么工作的 ?
调用 add(3, 4) 这个场景 既然想传入 3, 4 那么 T 类型就是 int 所有编译器会根据 add(T a, T b) 函数实例化出来一个代码
*/
cout << " add(3, 4) = " << add(3, 4) << endl;
return 0;
}

ENDS(test1)

int main() {
test1::main();
return 0;
}

查看模板实例化后的方法

查看可执行程序中的若干个符号的定义

1
nm -C a.out

当我们在使用模板方法的时候,使用其实不是模板方法而是模板生成的那一段具体的代码

add(3, 4) 调用形式

为什么编译器它会实例话出来 $add$就是通过调用形式完成的模板类型自动推到,看3是什么类型在看4是什么类型(int),这个时候模板当中那个参数推到是不存在冲突的这时候才会生成一个$add$

1
2
3
4
5
6
// 可以看成c++重载的一种高级表现
int main() {
cout << " add(3, 4) = " << add(3, 4) << endl;
cout << "add(3.1, 4.2) = " << add(3.1, 4.2) << endl;
return 0;
}

image-20220722220152135

模板函数-代码合集

  • decltype: 根基表达式推导类型(不进行表达式计算, 不进行表示执行,不执行但是也保证这段代码是不违法的)
  • auto(可以在声明变量的时候根据变量初始值的类型自动推到) + decltype 返回值后置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/*************************************************************************
> File Name: 1.template.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月22日 星期五 20时47分36秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x{
#define ENDS(x) } // end of namespace x

BEGINS(test1)

// typename 只是说明 T 是一个类型
// 这里typename T 还可以写成 class T 作用是一模一样的(未来可能会 有区别)
// template<class T>
template<typename T>

T add(T a, T b) {
return a + b;
}

int main() {
// 推到没有冲突
cout << " add(3, 4) = " << add(3, 4) << endl;
cout << "add(3.1, 4.2) = " << add(3.1, 4.2) << endl;
// 推到有冲突
// int double 同一个编译器函数有两种含义 编译器就懵逼了 (隐士推到)
// cout << "add(3, 4.2) = " << add(3, 4.2) << endl;

// 显示调用 add<double>模板
cout << "add(3, 4.2) = " << add<double>(3, 4.2) << endl;
return 0;
}

ENDS(test1)

BEGINS(test2)

class A {
public :
A() = delete;
A(int x) : x(x) {}
int x;
};

class B {
public :
B() = delete;
B(int x) : x(x) {}
int x;
};

class C {
public :
C() = delete;
C(int x): x(x) {}
int x;
};


C operator+(const A &a, const B &b) {
return C(a.x + b.x);
}

C operator+(const B &a, const A &b) {
return C(a.x + b.x);
}


// 使用两个参数这种, 返回类型没法确定
// decltype 如果T和U没有构造函数那就出错了
//template<typename T, typename U>
// 两个类型不能+的 但是可以调用构造函数
/*
decltype(T() + U()) add(T a, U b) {
return a + b;
}
*/

ostream &operator<<(ostream &out , const C &c) {
out << "Class C.x = " << c.x;
return out;
}

template<typename T, typename U>
// 返回值后置
auto add(T a, U b) -> decltype(a + b) {
return a + b;
}

template<typename T>
void judge(T a) {
cout << "unknow type" << endl;
return ;
}

template<>
void judge(int a) {
cout << "int type" << endl;
return ;
}

template<>
void judge(double a) {
cout << "double type" << endl;
}


int main() {
cout << " add(3, 4) = " << add(3, 4) << endl;
cout << "add(3.1, 4.2) = " << add(3.1, 4.2) << endl;
cout << "add(3, 4.2) = " << add<double>(3, 4.2) << endl;
cout << "add(3, 4.2) = " << add(3, 4.2) << endl;

A a(56);
B b(78);
// decltype(T() + U()) 不执行但是也保证这段代码是不违法的
cout << "add(A, B) = " << add(a, b) << endl;

// 类型朽化: 根基表达式推导类型
// decltype 不进行表达式计算, 不进行表示执行
// 它只看一眼不进行计算执行
do {
decltype(3 + 4.2) a;
decltype(4.2 + 3) b;
decltype(3 + 4) c;
decltype(string("abc") + string("def")) d;
judge(a), judge(b), judge(c), judge(d);
} while(0);

return 0;
}

ENDS(test2)

int main() {
// 函数模板
// test1::main();
// 没有bug的函数模板
test2::main();
return 0;
}

模板类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
//  模板类的定义使用
BEGINS(test3)

// 可以打印任意类型的模板类对象
template<typename T>
class PrintAnt {
public :
PrintAnt(ostream &out) : out(out) {}
PrintAnt &Print(T a) {
out << a;
return *this;
}
PrintAnt &endl() {
out << std::endl;
return *this;
}
private :
ostream &out;
};

int main() {
// 模板类与模板函数不一样要明确类型
PrintAnt<int> pint(cout);
PrintAnt<double> pdouble(cout);
PrintAnt<string> pstring(cout);
pint.Print(3).endl();
pdouble.Print(3.3).endl();
pstring.Print("hello world").endl();
return 0;
}

ENDS(test3)


BEGINS(test4)
// 可以打印任意类型的模板类对象
class PrintAnt {
public :
PrintAnt(ostream &out) : out(out) {}
// 模板方法
template<typename T>
PrintAnt &Print(T a) {
out << a;
return *this;
}
PrintAnt &endl() {
out << std::endl;
return *this;
}
private :
ostream &out;
};


int mian() {
PrintAnt p(cout);
p.Print(3).endl().Print(3.3).endl().Print("hello world").endl();

return 0;
}

ENDS(test4)

int main() {
// 模板类的定义使用
// test3::main();
test4::mian();
return 0;
}

左值、右值、移动构造

常态 临时
值: 左值 右值
引用: 左值引用 右值引用

这是四个概念

如果一个值是左值话那么它将优先绑定函数的佐值引用版本

如果一个值是右值话那么它将优先绑定函数的右值引用版本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
/*************************************************************************
> File Name: 2.rvalue_mov.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月23日 星期六 10时46分48秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace

BEGINS(test1)

void judge2(int &x) {
cout << "(left value - 2) : ";
return ;
}

// 右值引用
void judge2(int &&x) {
cout << "(right valie - 2) : ";
}


// 左值引用
void judge(int &x) {
// 左值是和右值是有作用域 所以说当在前作用域是左值
// judge2(x);

judge2(x);
cout << "left value" << endl;
return ;
}

// 右值引用
void judge(int &&x) {
// move 会把任何表达式直接变成右值
// judge2(move(x));

// forward 想要变成左值或者右值 显示形式表现出来
judge2(forward<int &&>(x));
cout << "right valie" << endl;
}

#define TEST(a) { \
cout << "judge " << #a << " : "; \
judge(a); \
}

int main() {
int n = 123;
(n += 2) = 100;
cout << n << endl;
// 左值
TEST(n);
// 因为 n + 1 会创建一个临时变量存储 所以在代码下一行无法通过单一变量n访问
TEST(n + 1);
TEST(n++);
TEST(++n);
TEST(1 + 2);
TEST(n += 2);

return 0;
}

ENDS(test1)

int main() {
test1::main();
return 0;
}

怎么判断是不是左值:

​ 最简单的判断依据就是当前表达式能不能放到运算符的左面,如果一个表达式能放到赋值运算符的左面那么他就是一个左值

左值表常态、右值表临时

左值:

当代码到了下一行的时候,我们上一行的表达的值我是否还能通过单一变量访问道

列:

​ int n = 123;

​ n += 2;

​ 可以用过 n 访问到(左值表常态)


​ int n = 123;

​ n + 1;

​ 因为(n + 1)会存储在一个临时变量上的,所以它是一个右值因为(右值表临时)

左值:-> 返回引用

右值:-> 返回值

运算符重载返回左值右值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespaces
BEGINS(test2)

class Point;

// 左值引用
void judge(Point &x) {
cout << "left value" << endl;
return ;
}

// 右值引用
void judge(Point &&x) {
cout << "right valie" << endl;
}

#define TEST(a) { \
cout << "judge " << #a << " : "; \
judge(a); \
}


class Point {
public :
Point(int x = 0, int y = 0) : __x(x), __y(y) {}
int x() { return __x; }
int y() { return __y; }
// 要是返回 Point 就是右值,要是返回&就是左值
Point &operator+=(int d) {
__x += d;
__y += d;
return *this;
}
Point operator+(int d) {
return Point(__x + d, __y + d);
}
private :
int __x, __y;

};


int main() {
Point p(3, 4);
TEST(p);
TEST(p += 1);
TEST(p + 1);
return 0;
}

ENDS(test2)

int main() {
// test1::main();
test2::main();
return 0;
}

右值->移动构造

移动构造相当于

一个师傅一个徒弟,那么师傅要四了说要把把毕生绝学都传给徒弟那么传给徒弟两种方式

  1. 嘴述,完了徒弟自己去练(相当于深拷贝)、(效率底)、(O(n))
  2. 直接内力传送完,师傅也就挂掉了一身功力就全都传给徒弟了师傅就什么都没有了(相当于右值直接移动构造)、(效率很高)、(O(1))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/*************************************************************************
> File Name: 2.rvalue_mov.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月23日 星期六 10时46分48秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace

BEGINS(test3)

// template<typename T>
class Array {

public :
Array(int n = 5) :__size(n), data(new int[n]) {
cout << this << " : default constructor" << endl;
}

// 针对左值处理的拷贝构造
Array(const Array &a) : __size(a.__size), data(new int[__size]) {
for(int i = 0; i < __size; i++) {
// data[i] = a[i];
new (data + i) int(a[i]);
}
cout << this << " : deep copy constructor" << endl;
return ;
}

// move constructor(移动构造)
Array(Array &&a) : __size(a.__size), data(a.data) {
a.data = nullptr;
a.__size = 0;
cout << "move constructor " << endl;
return ;
}

int size() { return __size; }

int &operator[](int ind) const { return data[ind]; }

Array operator+(Array &a) {
Array ret(__size + a.__size);
for(int i = 0; i < __size; i++) {
ret[i] = data[i];
}
for(int i = __size; i < ret.size(); i++) {
ret[i] = a.data[i - __size];
}
return ret;
}

~Array() {
cout << this << " : destructor" << endl;
delete [] data;
return ;
}

private :
int __size, *data;

};

int main() {
Array a, b;
Array c = a + b;
// 如果说a在之后就不使用了那么就可以变成右值的拷贝
Array d(move(a));
return 0;
}

ENDS(test3)

int main() {
// test1::main();
// 运算符重载返回左值右值
//test2::main();
test3::main();
return 0;
}

模板的特化、偏特化

类模板:特化 (全特化)、偏特化

函数模板:特化 (全特化)

特化:就好比机场的VIP通道给少数人准备

模板(全特化): 所以的参水都被固定了

有template关键字就是一个模板

image-20220723150640097

模板的特化、偏特化-代码实现

  • test1-函数模板、(特化)全特化
  • test2-模板类模板、(特化)全特化、偏特化
  • test3-((特化)全特化、偏特化)实现判断相关的类型有没有构造函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
/*************************************************************************
> File Name: 3.specialization.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月23日 星期六 15时08分41秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace

BEGINS(test1)

template<typename T>
T add(T a, T b) {
return a + b;
}

// 模板的全特化版本 模板参数都被固定下来
template<>
int add(int a, int b) {
cout << "int template" << endl;
return a + b;
}

int main() {
// add<int>
cout << add(3, 4) << endl;
//add<double>
cout << add(3.1, 4.1) << endl;

return 0;
}

ENDS(test1)

BEGINS(test2)

template<typename T, typename U>
class Test {
public :
Test() {
cout << "normal template<T, U> " << endl;
}
};

// 全特化
template<>
class Test<int, double> {
public :
Test() {
cout << "specialization template<int, double> " << endl;
}
};

// 偏特化
template<typename T>
class Test<int, T> {
public :
Test() {
cout << "partial specialization template<int, T> " << endl;
}
};

int main() {
// 正常
Test<string, int> t1;
// 全特化
Test<int, double> t2; // ?
// 偏特化
Test<int, string> t3;
// 优先级: 全 -> 偏 -> 正常模板
return 0;
}

ENDS(test2)

BEGINS(test3)

class A {};
class B {};


class yes_constructor {

public :
static const char *has_constructor;
};
const char *yes_constructor::has_constructor = "yes";

class no_constructor {

public :
static const char *has_constructor;
};
const char *no_constructor::has_constructor = "no";

template <typename T>
class type_trais : public yes_constructor {};

// *
template <typename T>
class type_trais<T *> : public no_constructor{};

// int
template <>
class type_trais<int> : public no_constructor{};

// double
template <>
class type_trais<double> : public no_constructor {};

/*
template <typename T>
class type_trais {
public:

static const char *has_constructor;
};

template<typename T>
const char *type_trais<T>::has_constructor = "yes";

// *
template <typename T>
class type_trais<T *> {
public:

static const char *has_constructor;
};

template<typename T>
const char *type_trais<T *>::has_constructor = "no";
// int
template <>
class type_trais<int> {
public:

static const char *has_constructor;
};

const char *type_trais<int>::has_constructor = "no";

// double
template <>
class type_trais<double> {
public:

static const char *has_constructor;
};

const char *type_trais<double>::has_constructor = "no";
*/

#define TEST(type) \
cout << #type << " : "<< type_trais<type>::has_constructor << endl;

int main() {
TEST(int);
TEST(A);
TEST(double);
TEST(B);
TEST(string);
TEST(string *);

// cout << type_trais<B>::has_constructor << endl; // yes

return 0;
}

#undef TEST

ENDS(test3)

BEGINS(test4)

class A {};
class B {};


class yes_constructor {};
class no_constructor {};

template <typename T>
class type_trais {
public :
typedef yes_constructor has_constructor;
};

// *
template <typename T>
class type_trais<T *> {
public :
typedef no_constructor has_constructor;
};

// int
template <>
class type_trais<int> {
public :
typedef no_constructor has_constructor;
};

// double
template <>
class type_trais<double> {
public :
typedef no_constructor has_constructor;
};


ostream &operator<<(ostream &out, const no_constructor &) {
out << "yes";
return out;
}

ostream &operator<<(ostream &out, const yes_constructor &) {
out << "no";
return out;
}


#define TEST(type) \
cout << #type << " : "<< type_trais<type>::has_constructor() << endl;

int main() {
TEST(int);
TEST(A);
TEST(double);
TEST(B);
TEST(string);
TEST(string *);

// cout << type_trais<B>::has_constructor << endl; // yes

return 0;
}

ENDS(test4)

int main() {
// 函数模板全特化
// test1::main();
// 模板类
// test2::main();
// 判断相关的类型有没有构造函数
//test3::main();
test4::main();
return 0;
}

可变参数模板

1
2
3
4
5
6
7
template<typename T, typename ...ARGS>
// ARGS (类型集合)... args (变量集合)
void Print(const T &a, ARGS... args) {
cout << a << endl;
Print(args...);
return ;
}

代码解释:

​ **ARGS(类型集合)**代表模板中剩余部分的类型数量是可变的,但最少为1个。

​ 此代码会递归展开模板函数Print

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
/*************************************************************************
> File Name: 4.template_args.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月23日 星期六 22时03分13秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) }

BEGINS(test1)

class A {
public :
A(int x, int y) : x(x), y(y) {}
int x, y;
};

ostream &operator<<(ostream &out, const A &a) {
out << "Class A : " << a.x << ", " << a.y;
return out;
}


template<typename T>
void Print(T a) {
cout << a << endl;
return ;
}

template<typename T, typename ...ARGS>
void Print(T a, ARGS... args) {
cout << a << " | ";
// 没有终止条件实现一个类似重载
Print(args...);
return ;
}


int main() {
A a(5, 6);
Print("hello world");
Print("hello world", 3, 3.4, a);
Print(3, a, 6.1, "ttw");
return 0;
}

ENDS(test1)


int main() {
// 打印任意参数
test1::main();
return 0;
}

代码合集

  • test1::打印任意参数
  • test2::分析变参模板的参数
  • test3::可变参数扩充实现智能传入3个参数
  • test4::可变参数扩充 类似function
  • test5::编译期常量
  • test6::变参模板
1
2
3
4
5
6
// 打印任意参数
// test1::main();
// 分析变参模板的参数
// test2::main();
// function
// test4::mian();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
BEGINS(test2)

template<typename T, typename ... ARGS>
class ARG {
public :
typedef T type;
typedef ARG<ARGS...> rest;
};

template<typename T>
class ARG<T> {
public :
typedef T type;
};

template<typename T, typename ...ARGS>
class Test {
public :
// ARG(ARGS) 工具模板类 功能:↓
// 获取ARGS变参列表中第一个类型和第二个类型
T operator()(typename ARG<ARGS...>::type a, typename ARG<ARGS...>::rest::type b) {
return a + b;
}
};

int main() {
// 传入2个int返回一个int类型
Test<int, int, int> t1;
// 传入double类型int类型返double类型
Test<double, double, int> t2;
cout << t1(3, 4) << endl;
cout << t2(3.5, 4) << endl;
return 0;
}

ENDS(test2)

BEGINS(test3)

template<typename T, typename ... ARGS>
class ARG {
public :
typedef T type;
typedef ARG<ARGS...> rest;
};

template<typename T>
class ARG<T> {
public :
typedef T type;
typedef T ftype;
};


template<typename T, typename ...ARGS>
class Test {
public :
// ARG(ARGS) 工具模板类 功能:↓
// 获取ARGS变参列表中第一个类型和第二个类型
T operator()(typename ARG<ARGS...>::type a, typename ARG<ARGS...>::rest::ftype b) {
return a + b;
}
};

int main() {
// 传入2个int返回一个int类型
Test<int, int, int> t1;
// 传入double类型int类型返double类型
Test<double, double, int> t2;
// Test<double, int, int, int> t3;
cout << t1(3, 4) << endl;
cout << t2(3.5, 4) << endl;
return 0;
}

ENDS(test3)

BEGINS(test4)

template<typename T, typename ... ARGS>
class ARG {
public :
typedef T type;
typedef ARG<ARGS...> rest;
};

template<typename T>
class ARG<T> {
public :
typedef T type;
typedef T ftype;
};


template<typename T, typename ...ARGS> class Test;
template<typename T, typename ...ARGS>
class Test<T(ARGS...)> {
public :
// ARG(ARGS) 工具模板类 功能:↓
// 获取ARGS变参列表中第一个类型和第二个类型
T operator()(typename ARG<ARGS...>::type a, typename ARG<ARGS...>::rest::ftype b) {
return a + b;
}
};

int main() {
/*
// 传入2个int返回一个int类型
Test<int, int, int> t1;
// 传入double类型int类型返double类型
Test<double, double, int> t2;
// Test<double, int, int, int> t3;
*/
Test<int(int, int)> t1;
Test<double(int, int)> t2;
cout << t1(3, 4) << endl;
cout << t2(3.5, 4) << endl;
return 0;
}

ENDS(test4)

BEGINS(test5)

template<int M>
void Print() {
cout << M << ", ";
Print<M - 1>();
}

template<>
void Print<1>() {
cout << 1 << endl;
return ;
}

int main() {
Print<5>();
Print<15>();
Print<2>();
Print<10>();
return 0;
}

ENDS(test5)

BEGINS(test6)

template<int N, typename T, typename ...ARGS>
struct ARG {
typedef typename ARG<N - 1, ARGS...>::type type;
};

template<typename T, typename ...ARGS>
struct ARG<1, T, ARGS...> {
typedef T type;
};

template<typename T>
struct ARG<1, T> {
typedef T type;
};

template<typename T, typename ...ARGS>
struct NUM_ARGS {
static constexpr int r = NUM_ARGS<ARGS...>::r + 1;
};

template<typename T>
struct NUM_ARGS<T> {
static constexpr int r = 1;
};

template<int N>
struct Zero {
typedef int no;

};

template<>
struct Zero<0> {
typedef int yes;

};

template<typename T, typename ...ARGS> class Test;
template<typename T, typename ...ARGS>
class Test<T(ARGS...)> {
public :
typedef typename Zero<2 - NUM_ARGS<ARGS...>::r>::yes TYPE_NUM_2;
T operator()(
typename ARG<1, ARGS...>::type a,
typename ARG<2, ARGS...>::type b) {
return a + b;
}
};

int main() {
Test<int(int, int)> t1;
// Test<bool(int, int, int)> t2;
cout << t1(3, 2);

return 0;
}

ENDS(test6)

int main() {
// 打印任意参数
// test1::main();
// 分析变参模板的参数
// test2::main();
// function
// test4::mian();
// 编译期常量
//test5::main();
test6::main();
return 0;
}

模板练习-代码

  • test1::实现一个模板进行累加求和
  • test2::判断一个数字是不是偶数
  • test3::判断一个数字的范围
  • test4::判断一个数字是不是素数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
/*************************************************************************
> File Name: 5.final_template_test.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月24日 星期日 15时39分20秒
************************************************************************/

#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x

// 实现一个模板进行累加求和
BEGINS(test1)
template<int n>
class sum {
public :
static constexpr int r = sum<n - 1>::r + n;

};

template <>
class sum<1> {
public :
static constexpr int r = 1;

};

int main() {
cout << sum<5>::r << endl; // sum of 1 - 5
cout << sum<7>::r << endl; // sum of 1 - 7
cout << sum<100>::r << endl; // sum of 1 - 100
return 0;
}

ENDS(test1)

// 判断一个数字是不是偶数
BEGINS(test2)
template<int N>
struct YES_OR_NO {
static const char *r;
};

template<int N>
const char *YES_OR_NO<N>::r = "no";
template<>
const char *YES_OR_NO<0>::r = "yes";

template<int n>
class is_even {
public :
static const char *r;
};

template<int N>
const char *is_even<N>::r = YES_OR_NO<N % 2>::r;

int main() {
cout << is_even<5>::r << endl; // no
cout << is_even<6>::r << endl; // yes
return 0;
}

ENDS(test2)

// 判断一个数字的范围
BEGINS(test3)
template<int n>
class score_judge {
public :
static constexpr const char *r = ( n>= 60) ? "good" : "bad";
};

int main() {
cout << score_judge<60>::r << endl; // good
cout << score_judge<54>::r << endl; // bad
return 0;
}

ENDS(test3)


// 判断一个数字是不是素数
BEGINS(test4)

template<int i, int N>
class getNext {
public :
static constexpr int r = (N % i ? i + 1 : 0);
};

template<int i, int N>
class test {
public:
static constexpr const char *r
= ((i * i) > N ? "yes" : test<getNext<i, N>::r, N>::r);
};

template<int N>
class test<0, N> {
public :
static constexpr const char *r = "no";
};


template<int N>
class is_prime {
public :
static constexpr const char *r = test<2, N>::r;
};


int main() {
cout << "2 : "<< is_prime<2>::r << endl; // yes
cout << "3 : "<< is_prime<3>::r << endl; // yes
cout << "4 : "<< is_prime<5>::r << endl; // yes
cout << "8 : "<< is_prime<8>::r << endl; // no
cout << "103 : "<< is_prime<103>::r << endl; // yes
return 0;
}
ENDS(test4)


int main() {
// 实现一个模板进行累加求和
test1::main();
cout << "---------------- 分割线 -------------------" << endl;
// 判断一个数字是不是偶数
test2::main();
cout << "---------------- 分割线 -------------------" << endl;
// 判断一个数字的范围
test3::main();
cout << "---------------- 分割线 -------------------" << endl;
// 判断一个数字是不是素数
test4::main();
return 0;
}

模板引用

引用折叠

​ 再模板中如果是奇数个就是左值引用,偶数个是右值引用

// 模板中接收的是一个引用是&&, 而不是传统意义上右值引用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <iostream>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespac

template<typename T>
// 模板中接收的是一个引用是&&, 不是左值引用或者是右值引用
BEGINS(reference_param)

template<typename T>
struct remove_reference {
typedef T type;
};

template<typename T>
struct remove_reference<T &> {
typedef T type;
};

template<typename T>
struct remove_reference<T &&> {
typedef T type;
};

template<typename T>
// 当前这个模板接收的是一个引用, 不是左值引用或者是右值引用
void func(T &&a) {
typename remove_reference<T>::type c;
cout << "function T& a = " << a << endl;
return ;
}

int main() {
int n = 123;
func(n);
func(123);
// 左值引用 去掉&
typename remove_reference<int &&>::type a;
// 右值引用 去掉&&
typename remove_reference<int &>::type b;
typename remove_reference<int>::type c;
return 0;
}

ENDS(reference_param)

image-20220724214117408

image-20220724215916620

代码合集-function(手动实现)

  • reference_param::去掉&
  • bind_usage::bind 方法 将函数和相关的参数打包绑定
  • addConst::添加const限定
  • addLvalueReference::转换成左值引用
  • removePointer::去掉 *
  • function_impl::function_手动实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
/*************************************************************************
> File Name: 6.function.cpp
> Author: 秃头王
> Mail: 1658339000@qq.com
> Created Time: 2022年07月24日 星期日 21时18分55秒
************************************************************************/

#include <iostream>
#include <functional>
using namespace std;

#define BEGINS(x) namespace x {
#define ENDS(x) } // end of namespace x
/*
BEGINS(reference_param)

template<typename T>
struct remove_reference {
typedef T type;
};

template<typename T>
struct remove_reference<T &> {
typedef T type;
};

template<typename T>
struct remove_reference<T &&> {
typedef T type;
};

template<typename T>
// 当前这个模板接收的是一个引用, 不是左值引用或者是右值引用
void func(T &&a) {
typename remove_reference<T>::type c;
cout << "function T& a = " << a << endl;
return ;
}

int main() {
int n = 123;
func(n);
func(123);
// 左值引用 去掉&
typename remove_reference<int &&>::type a;
// 右值引用 去掉&&
typename remove_reference<int &>::type b;
typename remove_reference<int>::type c;
return 0;
}

ENDS(reference_param)

// 添加const限定
BEGINS(addConst)

template<typename T>
struct add_const {
typedef const T type;
};
// 为什么还有个偏特化 const T 传入上面的类模板中中就 会变参 const const T
template<typename T>
struct add_const<const T> {
typedef const T type;
};

template<typename T>
void func(T a) {
typename add_const<T>::type c = 456;
// c = 890;
cout << "function T& a = " << a << endl;
return ;
};


int main() {
int n = 123;
func(n);
return 0;
}
ENDS(addConst)


// 转换成左值引用
BEGINS(addLvalueReference)

template<typename T>
struct add_lvalue_reference {
typedef T & type;
};

template<typename T>
struct add_lvalue_reference<T &> {
typedef T & type;
};

template<typename T>
struct add_lvalue_reference<T &&> {
typedef T & type;
};

template<typename T>
void func(T &&a) {
cout << "function T& a = " << a << endl;
return ;
}

int main() {
func(123);
return 0;
}

ENDS(addLvaluerReference)

// 去掉 *
BEGINS(removePointer)

template<typename T>
struct remove_pointer {
typedef T type;
};

template<typename T>
struct remove_pointer<T *> {
// 吧T类型的也去掉
typedef typename remove_pointer<T>::type type;
};

int main() {
cout << sizeof(typename remove_pointer<int>::type) << endl;
cout << sizeof(typename remove_pointer<int *>::type) << endl;
cout << sizeof(typename remove_pointer<int **>::type) << endl;
cout << sizeof(typename remove_pointer<int ***>::type) << endl;

return 0;
}

ENDS(removePointer)

// bind 方法 将函数和相关的参数打包绑定
BEGINS(bind_usage)

int add(int a, int b) {
cout << "add(a, b) = ";
return a + b;
}

void add_one(int &n) {
n += 1;
return ;
}


void func(int n, const char *msg) {
cout << n << " " << msg << endl;
return ;
}

int main() {
// bind 使用
auto t1 = bind(add, 3, 4);
cout << t1() << endl;
cout << t1() << endl;
cout << t1() << endl;

int n = 1;
cout << "n = " << n << endl;
// 加上 ref() 才是引用传递而不是值传递
auto t2 = bind(add_one, ref(n));
t2();
t2();
t2();
cout << "after three times t2 function call,n = " << n << endl;

func(3, "hello world");
// bind 调整函数参数顺序
auto t3 = bind(func, std::placeholders::_4, std::placeholders::_1);
t3("hello world", 3, 5, 6, 7);
return 0;
}

ENDS(bind_usage)
*/
BEGINS(function_impl)

template<typename T, typename ...ARGS>
class Base {
public :
virtual T run(ARGS...) = 0;
virtual Base<T, ARGS...> *getCopy() = 0;
virtual ~Base(){}
};

template<typename T, typename ...ARGS>
class normal_function : public Base<T, ARGS...> {
public :
normal_function(T(*ptr)(ARGS...)) : func(ptr) {}
T run(ARGS... args) override {
return func(forward<ARGS>(args)...);
}
Base<T, ARGS...> *getCopy() override {
return new normal_function(*this);
}

private :
T (*func)(ARGS...);
};

template<typename CLASS_T, typename T, typename ...ARGS>
class functor : public Base<T, ARGS...> {
public :
functor(CLASS_T obj) : obj(obj) {}
T run(ARGS... args) override{
return obj(forward<ARGS>(args)...);
}
Base<T, ARGS...> *getCopy() override {
return new functor(*this);
}
private :
CLASS_T obj;
};

template<typename T, typename ...ARGS> class function;
template<typename T, typename ...ARGS>
class function<T(ARGS...)> {
public :
// ptr 普通函数指针
function(T (*ptr)(ARGS...)) : ptr(new normal_function<T, ARGS...>(ptr)) {}

// obj 可调用对象
template<typename CLASS_T>
function(CLASS_T obj) : ptr(new functor<CLASS_T, T, ARGS...>(obj)){}

T operator()(ARGS... args) {
return ptr->run(forward<ARGS>(args)...);
}

function &operator=(const function<T(ARGS...)> &func) {
delete this->ptr;
this->ptr = func.ptr->getCopy();
return *this;
}
~function() {
delete this->ptr;
}
private :
Base<T, ARGS...> *ptr;

};

int func(int a, int b) {
cout << "normal function : ";
return a + b;
};

class ADD_MULT {
public :
ADD_MULT(int x) : x(x) {}
int operator()(int a, int b) {
cout << "functor : ";
return (a + b) * 2;
}
private :
int x;
};

int main() {
ADD_MULT add_mult(2);
function<int(int, int)> f1 = func;
function<int(int, int)> f2 = add_mult;
cout << f1(3, 4) << endl;
cout << f2(3, 4) << endl;
f1 = f2;
cout << f1(3, 4);

return 0;
}

ENDS(function_impl)

int main() {
// reference_param::main();
// bind_usage::main();
// addConst::main();
// addLvalueReference::main();
// removePointer::main();
function_impl::main();
return 0;
}

源码文件*.cpp

点我跳转:https://github.com/qzwl123/C-/tree/main/%E6%A8%A1%E6%9D%BF

评论