使用GNU C++编译器(g++)编译包含C++11语法特性的代码,需要加上“-std=c++11”编译选项。例如:
1g++ -std=c++11 hello.cpp
x1// auto1.cpp
2
3// auto的基本用法
4
5
6
7
8using namespace std;
9
10int main(void) {
11 auto a = 1; // a:int,常限定被丢弃
12 cout << typeid(a).name() << endl; // i
13
14 auto b = new auto(2); // b:int*
15 cout << typeid(b).name() << endl; // Pi
16
17 auto const* c = &a, d = 3; // c:int const*, d:int const
18 cout << typeid(c).name() << endl; // PKi
19 cout << typeid(d).name() << endl; // i
20 // cout << ++d << endl; // 编译错误,d带有常限定
21
22 // auto const* e = &a, f; // 编译错误,虽然根据e的初值&a已经可以推导出auto,但
23 // f仍然需要被显式初始化,且不能与之前的推断发生矛盾
24 // auto const* g = &a, h = 3.0; // 编译错误,类型推导不能有二义性
25
26 // 在旧语法中,auto变量即自动变量存储于栈区,而static变量即静态变量存储于
27 // 静态区,二者不可同时使用,但C++11的auto关键字已不再作为存储类型指示符
28
29 static auto i = 4.;
30 cout << typeid(i).name() << endl; // d
31
32 // auto int j; // 编译错误,C++11的auto关键字已不再作为存储类型指示符
33
34 // auto k; // 编译错误,auto并不能代表一个实际的类型声明,它只是一个类
35 // 型声明的占位符。使用auto声明的变量必须马上初始化,以让编
36 // 译器推断出它的实际类型,并在编译时将auto替换为真正的类型
37
38 return 0;
39}
xxxxxxxxxx
451// auto2.cpp
2
3// auto同指针或引用结合使用
4
5
6
7
8using namespace std;
9
10int main(void) {
11 int a = 0;
12
13 auto* b = &a; // auto=int, b:int*
14 cout << typeid(b).name() << endl; // Pi
15
16 // 即使不把auto声明为指针,其亦可被推导为指针类型
17
18 auto c = &a; // auto=int*, c:int*
19 cout << typeid(c).name() << endl; // Pi
20
21 // 当表达式带有引用属性时,auto会抛弃其引用属性,直接推导为原始类型
22
23 auto& d = a; // auto=int, d:int&
24 cout << &d << ' ' << &a << endl; // 0x7ffc19fd2540 0x7ffc19fd2540
25 auto e = d; // auto=int, e:int
26 cout << &e << ' ' << &d << endl; // 0x7ffc19fd2544 0x7ffc19fd2540
27
28 // 当表达式带有CV(只读/挥发)限定时,auto会抛弃其CV限定
29
30 auto const f = a; // auto=int, f:int const
31 // cout << ++f << endl; // 编译错误,f带有常限定
32 auto g = f; // auto=int, g:int
33 cout << ++g << endl; // 1
34
35 // 但如果auto和引用或指针结合使用,表达式的CV限定会被保留下来
36
37 auto const& h = a; // auto=int, h:int const&
38 // cout << ++h << endl; // 编译错误,h带有常限定
39 auto& i = h; // auto=int const, i:int const&
40 // cout << ++i << endl; // 编译错误,i带有常限定
41 auto* j = &h; // auto=int const, j:int const*
42 // cout << ++*j << endl; // 编译错误,j带有常限定
43
44 return 0;
45}
xxxxxxxxxx
631// auto3.cpp
2
3// auto使用的限制
4
5
6
7
8using namespace std;
9
10// auto不能用于函数的参数
11
12// void foo(auto a = 0) {
13// cout << typeid(a).name() << endl;
14// }
15
16class A {
17public:
18 int x = 0;
19
20 // auto不能用于类的非静态成员变量
21
22 // auto y = 1;
23
24 static auto const z = 2;
25};
26
27template<typename T>
28class B {
29public:
30 B(T const& arg) : var(arg) {}
31
32 T var;
33};
34
35int main (void) {
36 // auto不能用于函数的参数
37
38 // foo(1);
39
40 // auto不能用于类的非静态成员变量
41
42 A a;
43 cout << a.x << ' ' /*<< a.y << ' ' */<< a.z << endl; // 0 2
44
45 // auto不能用于模板的类型实参
46
47 B<int> b(0);
48 // B<auto> c = b;
49
50 // auto不能用于数组元素
51
52 int d[10];
53 // auto e[10] = d;
54
55 // 但可用于指向数组元素的指针和引用整个数组的引用
56
57 auto f = d; // auto=int*, arr3:int*, arr1代表数组首元素的地址
58 cout << typeid(f).name() << endl; // Pi
59 auto& g = d; // auto=int[10], arr4:int (&)[10], arr1代表数组整体
60 cout << typeid(g).name() << endl; // A10_i
61
62 return 0;
63}
xxxxxxxxxx
981// auto4.cpp
2
3// 何时使用auto?
4
5
6
7
8using namespace std;
9
10// 借助auto,可以减少模板的类型参数
11
12class A {
13public:
14 A(int arg = 0) : var(arg) {}
15
16 int get(void) const {
17 return var;
18 }
19
20 void set(int arg) {
21 var = arg;
22 }
23
24private:
25 int var;
26};
27
28class B {
29public:
30 B(char const* arg = "") : var(arg) {}
31
32 char const* get(void) const {
33 return var;
34 }
35
36 void set(char const* arg) {
37 var = arg;
38 }
39
40private:
41 char const* var;
42};
43
44template<typename V, typename X>
45void foo(X const& x) {
46 V var = x.get();
47 cout << var << endl;
48
49 // 使用var...
50}
51
52template<typename X>
53void bar(X const& x) {
54 auto var = x.get();
55 cout << var << endl;
56
57 // 使用var...
58}
59
60int main(void) {
61 // 借助auto,可以减少模板的类型参数
62
63 A a(1234);
64 B b("abcd");
65
66 foo<int>(a); // 1234
67 foo<char const*>(b); // abcd
68
69 bar(a); // 1234
70 bar(b); // abcd
71
72 // 借助auto,可以简化复杂类型的书写
73
74 multimap<string, int> sn;
75
76 sn.insert(make_pair("张飞", 100000));
77 sn.insert(make_pair("赵云", 150000));
78 sn.insert(make_pair("张飞", 200000));
79 sn.insert(make_pair("关羽", 250000));
80 sn.insert(make_pair("赵云", 300000));
81 sn.insert(make_pair("关羽", 350000));
82
83 pair<multimap<string, int>::iterator,
84 multimap<string, int>::iterator> range1 = sn.equal_range("张飞");
85 int sum1 = 0;
86 for (multimap<string, int>::iterator it = range1.first;
87 it != range1.second; ++it)
88 sum1 += it->second;
89 cout << sum1 << endl; // 300000
90
91 auto range2 = sn.equal_range("张飞");
92 int sum2 = 0;
93 for (auto it = range2.first; it != range2.second; ++it)
94 sum2 += it->second;
95 cout << sum2 << endl; // 300000
96
97 return 0;
98}
xxxxxxxxxx
431// decltype1.cpp
2
3// 计算表达式的类型
4
5
6
7
8using namespace std;
9
10int main(void) {
11 int a = 0;
12
13 // decltype的值就是表达式的类型本身
14
15 decltype(a) b = 1; // b:int
16 cout << typeid(b).name() << endl; // i
17
18 // decltype在编译时而非运行时计算表达式的类型
19
20 decltype(++a) c = a; // c:int&
21 cout << a << endl; // 0
22
23 // decltype会保留表达式的引用属性和CV限定
24
25 int const& d = 3;
26 decltype(d) e = d; // e:int const&
27 cout << &e << ' ' << &d << endl; // 0x7ffcf815f3dc 0x7ffcf815f3dc
28 // cout << ++e << endl; // 编译错误,e带有常限定
29
30 // decltype可以和指针联用
31
32 decltype(a) *f = &a, **g = &f; // f:int*, g:int**
33 cout << typeid(f).name() << endl; // Pi
34 cout << typeid(g).name() << endl; // PPi
35
36 // decltype可以和引用及CV限定符联用
37
38 decltype(a) const& h = a; // h:int const&
39 cout << &h << ' ' << &a << endl; // 0x7ffcf815f3d8 0x7ffcf815f3d8
40 // cout << ++h << endl; // 编译错误,h带有常限定
41
42 return 0;
43}
xxxxxxxxxx
991// decltype2.cpp
2
3// 类型计算规则
4
5
6
7using namespace std;
8
9class Obj {
10public:
11 Obj(int arg) : var(arg) {}
12
13 int var;
14
15 static int const sta = 0;
16};
17
18ostream& operator<< (ostream& os, Obj const& obj) {
19 return os << '(' << obj.var << ',' << obj.sta << ')';
20}
21
22// 规则1:对标识符及成员标识符表达式,直接取表达式的类型
23
24void rule1(void) {
25 int a = 0;
26 int const volatile& b = a;
27
28 decltype(a) c = a; // c:int
29 decltype(b) d = b; // d:int const volatile&
30
31 Obj e = 1;
32 decltype(e.var) f = 2; // f:int
33 decltype(Obj::sta) g = 3; // g:int const
34
35 cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' <<
36 e << ' ' << f << ' ' << g << endl;
37}
38
39// 规则2:对函数调用表达式,取函数返回值的类型
40
41void rule2(void) {
42 int& lvr(void); // 返回左值引用
43 int&& rvr(void); // 返回右值引用
44 int prv(void); // 返回纯右值
45 Obj obj(void); // 返回类对象
46
47 int const& clvr(void); // 返回常左值引用
48 int const&& crvr(void); // 返回常右值引用
49 int const cprv(void); // 返回常纯右值
50 Obj const cobj(void); // 返回常类对象
51
52 int i = 0;
53 decltype(lvr()) a = i; // a:int&
54 decltype(rvr()) b = 1; // b:int&&
55 decltype(prv()) c = 2; // c:int
56 decltype(obj()) d = 3; // d:Obj
57
58 int j = 4;
59 decltype(clvr())e = j; // e:int const&
60 decltype(crvr())f = 5; // f:int const&&
61 decltype(cprv())g = 6; // g:int, 基本类型返回值忽略CV限定
62 decltype(cobj())h = 7; // h:Obj const, 类类型返回值CV限定有效
63
64 cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' <<
65 e << ' ' << f << ' ' << g << ' ' << h << endl;
66}
67
68// 规则3:对其它表达式,若表达式的类型为左值则取该类型的左值引用,否则取表达式的类型
69
70void rule3(void) {
71 int a = 0;
72
73 decltype(a) b = 1; // b:int, 根据规则1
74 decltype((a)) c = a; // c : int&, a是左值,因此括号表达式(a)
75 // 也是左值,由规则3,c的类型为左值引用
76
77 Obj const d = 2;
78 decltype(d.var) e = 3; // e:int, 根据规则1
79 decltype((d.var)) f = d.var; // f:int const&, 常对象的成员变量都是常
80 // 左值,由规则3,f的类型为常左值引用
81
82 int g = 4, h = 5;
83 decltype(++g) i = g; // i:int&
84 decltype(g++) j = 6; // j:int
85 decltype(g = h) k = g; // k:int&
86 decltype(g + h) l = 7; // l:int
87
88 cout << a << ' ' << b << ' ' << c << ' ' << d << ' ' <<
89 e << ' ' << f << ' ' << g << ' ' << h << ' ' <<
90 i << ' ' << j << ' ' << k << ' ' << l << endl;
91}
92
93int main(void) {
94 rule1();
95 rule2();
96 rule3();
97
98 return 0;
99}
xxxxxxxxxx
841// decltype3.cpp
2
3// 何时使用decltype?
4
5
6
7
8
9using namespace std;
10
11// 打印可写容器中的元素
12
13template<typename C>
14void printWritable(C& c) {
15 cout << "可写容器:";
16
17 for (typename C::iterator it = c.begin(); it != c.end(); ++it)
18 cout << *it << ' ';
19
20 cout << endl;
21}
22
23// 打印只读容器中的元素
24
25template<typename C>
26void printReadonly(C const& c) {
27 cout << "只读容器:";
28
29 for (typename C::const_iterator it = c.begin(); it != c.end(); ++it)
30 cout << *it << ' ';
31
32 cout << endl;
33}
34
35// 打印任意容器中的元素
36
37template<typename C>
38void print(C& c) {
39 cout << "任意容器:";
40
41 for (decltype(c.begin()) it = c.begin(); it != c.end(); ++it)
42 cout << *it << ' ';
43
44 cout << endl;
45}
46
47int main(void) {
48 vector<int> wv; // 可写容器
49 wv.push_back(10);
50 wv.push_back(20);
51 wv.push_back(30);
52 wv.push_back(40);
53 wv.push_back(50);
54 vector<int> const rv = wv; // 只读容器
55
56 printWritable(wv);
57 printReadonly(rv);
58
59 print(wv);
60 print(rv);
61
62 map<string, vector<int> > scores;
63 scores["张飞"].push_back(70);
64 scores["张飞"].push_back(85);
65 scores["赵云"].push_back(75);
66 scores["赵云"].push_back(90);
67 scores["关羽"].push_back(80);
68 scores["关羽"].push_back(95);
69
70 // ...
71
72 int sum1 = 0; // 在冗长的代码中确定某个变量的类型将十分困难
73 for (size_t i = 0; i < scores["张飞"].size(); ++i)
74 sum1 += scores["张飞"][i];
75 cout << sum1 << endl; // 155
76
77 decltype(scores)::mapped_type::value_type sum2 = // 通过decltype可以很方便地
78 decltype(scores)::mapped_type::value_type(); // 根据变量表达式计算其类型
79 for (size_t i = 0; i < scores["张飞"].size(); ++i)
80 sum2 += scores["张飞"][i];
81 cout << sum2 << endl; // 155
82
83 return 0;
84}
xxxxxxxxxx
421// decltype4.cpp
2
3// 返回类型后置
4
5
6
7
8using namespace std;
9
10template<typename X, typename Y>
11auto add(X const& x, Y const& y) -> decltype(x + y) {
12 return x + y;
13}
14
15double foo(int arg) {
16 return arg / 2.0;
17}
18
19int foo(double arg) {
20 return int(arg * 2);
21}
22
23template<typename T>
24auto bar(T const& arg) -> decltype(foo(arg)) {
25 return foo(arg);
26}
27
28int main(void) {
29 auto a = add(1, 0.5);
30 cout << typeid(a).name() << ' ' << a << endl; // d 1.5
31
32 auto b = add (1, 'A');
33 cout << typeid(b).name() << ' ' << b << endl; // i 66
34
35 auto c = bar(1);
36 cout << typeid(c).name() << ' ' << c << endl; // d 0.5
37
38 auto d = bar(0.5);
39 cout << typeid(d).name() << ' ' << d << endl; // i 1
40
41 return 0;
42}
xxxxxxxxxx
381// alias1.cpp
2
3// 不能用typedef为模板定义别名
4
5
6
7
8using namespace std;
9
10template<typename A, typename B>
11class X {};
12
13// 可以用typedef为具体类型定义别名
14
15typedef unsigned int uint_t;
16
17// 当然也包括由模板实例化产生的类
18
19typedef X<string, int> xsi_t;
20
21// 但不能用typedef为模板或部分模板定义别名
22
23// typedef X x_t;
24// typedef X<string, B> xs_t;
25
26int main(void) {
27 uint_t a; // a:unsigned int
28 xsi_t b; // b:X<string, int>
29 // x_t<string, int> c;
30 // xs_t<int> d;
31
32 cout << typeid(a).name() << endl;
33 cout << typeid(b).name() << endl;
34 // cout << typeid(c).name() << endl;
35 // cout << typeid(d).name() << endl;
36
37 return 0;
38}
xxxxxxxxxx
381// alias2.cpp
2
3// 可以用using为包括模板在内的任何类型定义别名
4
5
6
7
8using namespace std;
9
10template<typename A, typename B>
11class X {};
12
13// 可以用using为具体类型定义别名
14
15using uint_t = unsigned int;
16
17// 当然也包括由模板实例化产生的类
18
19using xsi_t = X<string, int>;
20
21// 甚至可以用using为模板或部分模板定义别名
22
23template<typename A, typename B> using x_t = X<A, B>;
24template<typename B> using xs_t = X<string, B>;
25
26int main(void) {
27 uint_t a; // a:unsigned int
28 xsi_t b; // b:X<string, int>
29 x_t<string, int> c; // c:X<string, int>
30 xs_t<int> d; // d:X<string, int>
31
32 cout << typeid(a).name() << endl;
33 cout << typeid(b).name() << endl;
34 cout << typeid(c).name() << endl;
35 cout << typeid(d).name() << endl;
36
37 return 0;
38}
在C++98/03中,只有类模板可以带有缺省模板参数,函数模板不能带有缺省模板参数。
xxxxxxxxxx
461// defparam1.cpp
2
3// C++98/03中的函数模板不能带有缺省模板参数
4
5
6
7
8using namespace std;
9
10// 在C++98/03中,只有类模板可以带有缺省模板参数
11
12template<typename A = int, typename B = double, typename C = string>
13class X {
14public:
15 static void foo(void) {
16 cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
17 }
18};
19
20// 在C++98/03中,函数模板不能带有缺省模板参数
21
22// template<typename A = int, typename B = double, typename C = string>
23// void foo(void) {
24// cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
25// }
26
27int main(void) {
28 // 在C++98/03中,只有类模板可以带有缺省模板参数
29
30 X<char, short, long>::foo();
31 X<char, short>::foo();
32 X<char>::foo();
33 X<>::foo(); // "<>"不可省略
34
35 // 在C++98/03中,函数模板不能带有缺省模板参数
36
37 // foo<char, short, long>();
38 // foo<char, short>();
39 // foo<char>();
40 // foo<>();
41 // foo();
42
43 return 0;
44}
45
46// g++ -std=c++98 defparam1.cpp
xxxxxxxxxx
821// defparam2.cpp
2
3// C++11中的类模板和函数模板都可以带有缺省模板参数
4
5
6
7
8using namespace std;
9
10// 在C++11中,类模板可以带有缺省模板参数
11
12template<typename A = int, typename B = double, typename C = string>
13class X {
14public:
15 static void foo(void) {
16 cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
17 }
18};
19
20// 在C++11中,函数模板也可以带有缺省模板参数
21
22template<typename A = int, typename B = double, typename C = string>
23void foo(void) {
24 cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
25}
26
27// 只要满足隐式推断的条件,函数模板参数的缺省值不是非写在参数表最后
28
29template<typename A = int, typename B, typename C = string>
30A bar(B b) {
31 cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
32
33 A a = A();
34 C c = C();
35
36 return a;
37}
38
39// 无法隐式推断的模板参数取缺省值,否则取隐式推断的
40// 类型。只要隐式推断生效,模板参数的缺省值即被忽略
41
42template<typename A = int, typename B = double, typename C = string>
43A hum(B b) {
44 cout << typeid(A).name() << ' ' << typeid(B).name() << ' ' << typeid(C).name() << endl;
45
46 A a = A();
47 C c = C();
48
49 return a;
50}
51
52int main(void) {
53 // 在C++11中,类模板可以带有缺省模板参数
54
55 X<char, short, long>::foo();
56 X<char, short>::foo();
57 X<char>::foo();
58 X<>::foo(); // "<>"不可省略
59
60 // 在C++11中,函数模板也可以带有缺省模板参数
61
62 foo<char, short, long>();
63 foo<char, short>();
64 foo<char>();
65 foo<>();
66 foo(); // "<>"可以省略
67
68 // 只要满足隐式推断的条件,函数模板参数的缺省值不是非写在参数表最后
69
70 bar<char, short, long>(100);
71 bar<char, short>(100);
72 bar<char>(100); // 隐式推断B=int
73 bar<>(100); // 隐式推断B=int
74 bar(100); // 隐式推断B=int
75
76 // 无法隐式推断的模板参数取缺省值,否则取隐式推断的
77 // 类型。只要隐式推断生效,模板参数的缺省值即被忽略
78
79 hum(100); // 隐式推断B=int,忽略其缺省值double
80
81 return 0;
82}
在C++98/03标准中,连续的两个右尖括号会被编译器解释为右移位操作符,而非模板实参表结束,因此它们之间至少应保留一个空格。
xxxxxxxxxx
371// delimiter1.cpp
2
3// C++98/03标准模板实参表的右尖括号
4
5
6
7
8using namespace std;
9
10template<typename T>
11void ptype(void) {
12 cout << typeid(T).name() << endl;
13}
14
15template<typename T>
16class Dummy {};
17
18template<int x>
19int square(void) {
20 return x * x;
21}
22
23int main(void) {
24 // 在C++98/03标准中,连续的两个右尖括号会被编译器解释为右移位
25 // 操作符,而非模板实参表结束,因此它们之间至少应保留一个空格
26
27 // ptype<Dummy<int>>(); // 编译错误
28 ptype<Dummy<int> >();
29
30 // 这里的">>"会被正确解释为右移位操作符
31
32 cout << square<6>>1>() << endl; // 9
33
34 return 0;
35}
36
37// g++ -std=c++98 delimiter1.cpp
在C++11标准中,要求编译器对模板的右尖括号做单独处理,使之能正确区分右移位操作符和模板实参表结束,因此无需再留空格。
xxxxxxxxxx
351// delimiter2.cpp
2
3// C++11标准模板实参表的右尖括号
4
5
6
7
8using namespace std;
9
10template<typename T>
11void ptype(void) {
12 cout << typeid(T).name() << endl;
13}
14
15template<typename T>
16class Dummy {};
17
18template<int x>
19int square(void) {
20 return x * x;
21}
22
23int main(void) {
24 // 在C++11标准中,要求编译器对模板的右尖括号做单独处理,使之
25 // 能正确区分右移位操作符和模板实参表结束,因此无需再留空格
26
27 ptype<Dummy<int>>();
28
29 // 如果不加小括号,这里的">>"会被错误解释为模板参数表结束和大于号,导致编译错误
30
31 // cout << square<6>>1>() << endl; // 编译错误
32 cout << square<(6>>1)> () << endl; // 9
33
34 return 0;
35}
在C++98/03中,对象初始化方法有很多种,每一种都有各自的适用范围和作用。没有任何一种初始化方法可以通用于所有情况。
xxxxxxxxxx
641// initlist1.cpp
2
3// C++98/03标准没有通用的初始化语法
4
5
6
7
8
9using namespace std;
10
11struct Student {
12 char name[256];
13
14 struct Date {int y, m, d;} bday;
15};
16
17class Complex {
18public:
19 Complex(double r = 0, double i = 0) : r(r), i(i) {}
20
21 // 有公有拷贝构造函数,不一定会被调用
22
23 Complex(Complex const& complex) : r(complex.r), i(complex.i) {
24 cout << "拷贝构造:" << &complex << "->" << this << endl;
25 }
26
27 friend ostream& operator<<(ostream& os, Complex const& complex) {
28 return os << '(' << complex.r << showpos << complex.i << noshowpos << "i)";
29 }
30
31private:
32 // 无公有拷贝构造函数,编译器一定报错
33
34 // Complex(Complex const& complex);
35
36 double r, i;
37};
38
39int main(void) {
40 int a = 123; // 赋值形式的初始化
41 cout << a << endl;
42
43 double b(1.23); // 构造形式的初始化
44 cout << b << endl;
45
46 int c[] = {100, 200, 300}; // 列表形式的初始化
47 copy(c, c + sizeof(c) / sizeof(c[0]), ostream_iterator<int>(cout, " "));
48 cout << endl;
49
50 Student d = {"张飞", {2011, 11, 11}}; // 列表形式的初始化
51 cout << d.name << ',' << d.bday.y << '-' << d.bday.m << '-' << d.bday.d << endl;
52
53 Complex e(1.2, 3.4); // 构造形式的初始化
54 cout << e << endl;
55
56 // 对拷贝构造函数的调用,可能会被优化掉,但对拷贝构造函数的语法检查,编译器依然会做
57
58 Complex f = Complex(1.2, 3.4); // 赋值形式的初始化
59 cout << f << endl;
60
61 return 0;
62}
63
64// g++ -std=c++98 initlist1.cpp
在C++11中,列表形式的初始化语法被大大扩充了,可用于任何类型对象及其数组的初始化,无论该对象或数组是被静态还是动态创建的。
xxxxxxxxxx
771// initlist2.cpp
2
3// C++11标准提供了通用的列表形式的初始化语法
4
5
6
7
8
9using namespace std;
10
11struct Student {
12 char name[256];
13
14 struct Date {int y, m, d;} bday;
15};
16
17class Complex {
18public:
19 Complex(double r = 0, double i = 0) : r(r), i(i) {}
20
21 Complex const operator+(Complex const& complex) const {
22 // 列表形式的初始化语法甚至可以用在函数的返回值上
23
24 return {r + complex.r, i + complex.i};
25 }
26
27 friend ostream& operator<< (ostream& os, Complex const& complex) {
28 return os << '(' << complex.r << showpos << complex.i << noshowpos << "i)";
29 }
30
31private:
32 // 无公有拷贝构造函数,编译器并不报错
33
34 Complex(Complex const& complex);
35
36 double r, i;
37};
38
39int main(void) {
40 int a = {123};
41 cout << a << endl;
42
43 double b{1.23}; // 左花括号前面的等号写不写都一样
44 cout << b << endl;
45
46 int c[]{100, 200, 300};
47 copy(c, c + sizeof(c) / sizeof(c[0]), ostream_iterator<decltype(*c)>(cout, " "));
48 cout << endl;
49
50 Student d{"张飞", {2011, 11, 11}};
51 cout << d.name << ',' << d.bday.y << '-' << d.bday.m << '-' << d.bday.d << endl;
52
53 Complex e{1.2, 3.4};
54 cout << e << endl;
55
56 Complex f = {1.2, 3.4}; // 左花括号前面有没有等号,都不需要拷贝构造
57 cout << f << endl;
58
59 cout << e + f << endl;
60
61 Complex* g {new Complex{1.2, 3.4}};
62 cout << *g << endl;
63 delete g;
64
65 g = new Complex[3]{{1.1, 2.2}, {3.3, 4.4}, {5.5, 6.6}};
66 copy(g, g + 3, ostream_iterator<decltype(*g)>(cout, " "));
67 cout << endl;
68 delete[] g;
69
70 cout << Complex{1.2, 3.4} << endl; // 匿名对象
71
72 Complex const (&h)[3]{{1.1, 2.2}, {3.3, 4.4}, {5.5, 6.6}}; // 匿名数组
73 copy(h, h + 3, ostream_iterator<decltype(*h)>(cout, " "));
74 cout << endl;
75
76 return 0;
77}
何为聚合类型?
任意类型(聚合类型或非聚合类型)的数组
满足以下条件的类:
无自定义构造函数
无私有或保护的非静态成员变量
无基类
无虚函数
无通过“=”或“{}”在声明的同时初始化的非静态成员变量
聚合类型的元素可以是聚合类型的也可以是非聚合类型的
对聚合类型使用列表初始化,相当于对其中的元素逐一初始化,而对非聚合类型使用列表初始化,则需要调用匹配的构造函数。
xxxxxxxxxx
661// initlist3.cpp
2
3// 聚合类型与非聚合类型的列表初始化
4
5
6
7using namespace std;
8
9// 非聚合类型基类
10
11class Base {
12public:
13 Base(int n) : n(n) { // 自定义构造函数
14 cout << "Base构造:" << this << endl;
15 }
16
17 virtual ostream& operator>>(ostream& os) const { // 虚函数
18 return os << n;
19 }
20
21private:
22 int n; // 私有的非静态成员变量
23};
24
25// 非聚合类型子类
26
27class Nonagg : public Base { // 有基类
28public:
29 Nonagg(int n, double d) : Base(n), d(d) { // 自定义构造函数
30 cout << "Nonagg构造:" << this << endl;
31 }
32
33 ostream& operator>>(ostream& os) const { // 虚函数
34 return Base::operator>>(os) << ' ' << d << ' ' << s;
35 }
36
37 char const* s = "ABC"; // 通过“=”在声明的同时初始化的非静态成员变量
38
39protected:
40 double d; // 保护的非静态成员变量
41};
42
43// 聚合类型
44class Aggreg {
45public:
46 ostream& operator>>(ostream& os) const {
47 return nonagg >> os << ' ' << n << ' ' << d << ' ' << s;
48 }
49
50 Nonagg nonagg; // 聚合类型可以包含非聚合类型的元素
51 int n;
52 double d;
53 char const* s;
54};
55
56int main(void) {
57 Nonagg nonagg{12, 3.4};
58
59 Base& base = nonagg;
60 base >> cout << endl;
61
62 Aggreg aggreg{{12, 3.4}, 56, 7.8, "DEF"};
63 aggreg >> cout << endl;
64
65 return 0;
66}
xxxxxxxxxx
941// initlist4.cpp
2
3// 变长初始化列表
4
5
6
7
8
9
10
11using namespace std;
12
13class Students {
14 using vs = vector<char const*>;
15 using sn = map<char const*, int>;
16
17public:
18 // 令构造函数接受initializer_list参数,以支持变长初始化列表
19
20 Students(initializer_list<vs::value_type> names) {
21 for (auto it = names.begin(); it != names.end(); ++it)
22 this->names.push_back(*it);
23 }
24
25 Students(initializer_list<sn::value_type> scores) {
26 for (auto it = scores.begin(); it != scores.end(); ++it)
27 this->scores.insert(*it);
28 }
29
30 void pnames(void) const {
31 copy(names.begin(), names.end(), ostream_iterator<decltype(*names.begin())>(cout, " "));
32 cout << endl;
33 }
34
35 void pscores(void) const {
36 for (auto it = scores.begin(); it != scores.end(); ++it)
37 cout << it->first << ':' << it->second << endl;
38 }
39
40private:
41 vs names;
42 sn scores;
43};
44
45// initializer_list不仅用于构造函数,任何需要传递变长同类型数据集的场合都可以使用
46
47int average(initializer_list<int> scores) {
48 int ave = 0;
49
50 for (auto it = scores.begin(); it != scores.end(); ++it)
51 ave += *it;
52
53 if (scores.size())
54 ave /= scores.size();
55
56 return ave;
57}
58
59int main (void) {
60 // 用于数组的初始化列表,其长度可以是不固定的
61
62 char const* a[]{"张飞", "赵云", "关羽", "黄忠", "马超"};
63 copy(a, a + sizeof(a) / sizeof(a[0]), ostream_iterator<decltype(a[0])>(cout, " "));
64 cout << endl;
65
66 // 用于标准容器的初始化列表,其长度同样可以是不固定的
67
68 vector<char const*> b{"张飞", "赵云", "关羽", "黄忠", "马超"};
69 copy(b.begin(), b.end(), ostream_iterator<decltype(b[0])>(cout, " "));
70 cout << endl;
71
72 map<char const*, int> c{
73 {"张飞", 50}, {"赵云", 60}, {"关羽", 70}, {"黄忠", 80}, {"马超", 90}};
74 for (auto it = c.begin(); it != c.end(); ++it)
75 cout << it->first << ':' << it->second << endl;
76
77 // 支持变长初始化列表的自定义类
78
79 Students d{"张飞", "赵云", "关羽", "黄忠", "马超"};
80 d.pnames();
81
82 Students e{
83 {"张飞", 50}, {"赵云", 60}, {"关羽", 70}, {"黄忠", 80}, {"马超", 90}};
84 e.pscores();
85
86 // 支持变长参数列表的自定义函数
87
88 cout << average({}) << endl;
89
90 int f = 60, g = 70, h = 80;
91 cout << average({50, f, g, h, 90}) << endl;
92
93 return 0;
94}
xxxxxxxxxx
661// initlist5.cpp
2
3// initializer_list轻量级类模板容器
4
5
6
7
8
9
10using namespace std;
11
12// 轻量级容器内部存放初始化列表元素的引用而非其拷贝
13
14initializer_list<int> light(void) {
15 int a = 1000, b = 2000, c = 3000;
16 return {a, b, c}; // 所返回局部变量的引用将在函数返回后失效
17}
18
19// 重量级容器内部存放初始化列表元素的拷贝而非其引用
20
21list<int> heavy(void) {
22 int a = 1000, b = 2000, c = 3000;
23 return {a, b, c}; // 所返回局部变量的拷贝在函数返回后依然有效
24}
25
26int main(void) {
27 // 可以接受任意长度的初始化列表({...}),但列表中元素的类型必须相同
28
29 initializer_list<int> in{10, 20, 30, 40, 50};
30
31 // 只有三个公有成员函数:begin(),end()和size()
32
33 copy(in.begin(), in.end(), ostream_iterator<decltype(*in.begin())>(cout, " "));
34 cout << '[' << in.size() << ']' << endl;
35
36 // 迭代器为只读类型,其目标元素不可修改
37
38 // for (auto it = in.begin(); it != in.end(); ++it)
39 // *it *= 100;
40
41 // 但可对容器整体赋值
42
43 in = {1000, 2000, 3000};
44 copy(in.begin(), in.end(), ostream_iterator<decltype(*in.begin())>(cout, " "));
45 cout << '[' << in.size() << ']' << endl;
46
47 // 提供缺省构造函数,用于实例化空容器
48
49 in = {};
50 copy(in.begin(), in.end(), ostream_iterator<decltype(*in.begin())>(cout, " "));
51 cout << '[' << in.size() << ']' << endl;
52
53 // 轻量级容器内部存放初始化列表元素的引用而非其拷贝
54
55 in = light();
56 copy(in.begin(), in.end(), ostream_iterator<decltype(*in.begin())>(cout, " "));
57 cout << '[' << in.size() << ']' << endl;
58
59 // 重量级容器内部存放初始化列表元素的拷贝而非其引用
60
61 list<int> ln = heavy();
62 copy(ln.begin(), ln.end(), ostream_iterator<decltype(*ln.begin())>(cout, " "));
63 cout << '[' << ln.size()<< ']' << endl;
64
65 return 0;
66}
xxxxxxxxxx
461// initlist6.cpp
2
3// 利用列表初始化防止类型收窄
4
5
6
7using namespace std;
8
9int main(void) {
10 // 常量及带有常限定的变量,根据值判定是否收窄,有信息损失则报错
11
12 int a = 1.2;
13 int b{1.2}; // 错误:从double到int需要收窄转换
14
15 float c = 1e40;
16 float d{1e40}; // 错误:从double到float需要收窄转换
17
18 float e = 1.2;
19 float f{1.2};
20
21 float g = (unsigned long long)-1;
22 float h{(unsigned long long)-1}; // 错误:从unsigned long long到float需要收窄转换
23
24 float i = (unsigned long long)1;
25 float j{(unsigned long long)1};
26
27 int const k = 128, l = 1;
28
29 char m = k;
30 char n{k}; // 错误:从int转换到char需要收窄转换
31
32 char o = l;
33 char p{l};
34
35 // 变量,根据类型判定是否收窄,有信息损失的风险即给出警告
36
37 int q = 128, r = 1;
38
39 char s = q;
40 char t{q}; // 警告:从int到char需要收窄转换
41
42 char u = r;
43 char v{r}; // 警告:从int到char需要收窄转换
44
45 return 0;
46}
xxxxxxxxxx
991// for1.cpp
2
3// 基于范围的for循环
4
5
6
7
8
9using namespace std;
10
11void print(int i) {
12 cout << i << ' ';
13}
14
15int main(void) {
16 int an[]{65, 66, 67, 68, 69};
17 size_t size = sizeof(an) / sizeof(an[0]);
18 vector<int> vn(an, an + size);
19
20 // 基于下标运算的for循环,不是所有的容器都支持下标运算,不通用
21
22 for (size_t i = 0; i < size; ++i)
23 cout << an[i] << ' ';
24 cout << endl;
25
26 for (size_t i = 0; i < size; ++i)
27 cout << vn[i] << ' ';
28 cout << endl;
29
30 // 基于迭代器的for循环,显式对迭代器做自增,需要理解迭代器运算
31
32 for (int* it = an; it != an + size; ++it)
33 cout << *it << ' ';
34 cout << endl;
35
36 for (vector<int>::const_iterator it = vn.begin(); it != vn.end(); ++it)
37 cout << *it << ' ';
38 cout << endl;
39
40 // 基于泛型算法的for循环,需指明容器两端,对全遍历而言过于繁冗
41
42 for_each(an, an + size, print);
43 cout << endl;
44
45 for_each(vn.begin(), vn.end(), print);
46 cout << endl;
47
48 // 基于范围的for循环,适用于包括数组在内的任何容器,既无需
49 // 使用迭代器,亦无需指明容器两端,通用,透明,且代码简洁
50
51 for (int n : an)
52 cout << n << ' ';
53 cout << endl;
54
55 for (int n : vn)
56 cout << n << ' ';
57 cout << endl;
58
59 // 撷取变量的类型,只要能从容器元素的类型做隐式转换即可,未必严格一致
60
61 for (char c : an)
62 cout << c << ' ';
63 cout << endl;
64
65 for (char c : vn)
66 cout << c << ' ';
67 cout << endl;
68
69 // 也可以使用auto关键字,让编译器根据容器元素的类型,自动推导出撷取变量的类型
70
71 for (auto n : an)
72 cout << n << ' ';
73 cout << endl;
74
75 for (auto n : vn)
76 cout << n << ' ';
77 cout << endl;
78
79 // 对于包含修改操作的循环,可以使用引用型撷取变量,引用容器中的每个元素
80
81 for (auto& n : an)
82 ++n;
83
84 for (auto& n : vn)
85 ++n;
86
87 // 即便是非修改循环,使用引用型撷取变量也有助于提高运行性能,特别是当容
88 // 器元素是复杂的类类型对象时。使用常引用还能防止对容器中元素的意外修改
89
90 for (auto const& n : an)
91 cout << n << ' ';
92 cout << endl;
93
94 for (auto const& n : vn)
95 cout << n << ' ';
96 cout << endl;
97
98 return 0;
99}
xxxxxxxxxx
631// for2.cpp
2
3// 范围循环的注意事项
4
5
6
7
8
9
10using namespace std;
11
12list<int> scores(void) {
13 cout << __FUNCTION__ << endl;
14
15 return {70, 75, 80, 85, 90, 95};
16}
17
18int main(void) {
19 // 对map和multimap容器使用范围循环,每次拿到的
20 // 元素既不是键也不是值,而是由键和值组成的pair
21
22 multimap<string, int> sn{
23 {"张飞", 70}, {"赵云", 75}, {"关羽", 80},
24 {"张飞", 85}, {"赵云", 90}, {"关羽", 95}};
25
26 for (auto kv : sn)
27 cout << kv.first << ':' << kv.second << endl;
28
29 // 对范围循环中的撷取变量使用auto关键字,其自动推导出的类型
30 // 是容器中的value_type,而非iterator,注意“.”和“->”的区别
31
32 for (auto kv = sn.begin(); kv != sn.end(); ++kv)
33 cout << kv->first << ':' << kv->second << endl;
34
35 // 在使用基于范围的for循环时,还需要注意容器本身的约束
36 /*
37 for (auto& kv : sn)
38 if (kv.first == "张飞")
39 kv.first = "黄忠"; // 编译错误,map/multimap中的键是只读的
40
41 set<int> numbers{10, 20, 30, 40, 50, 60};
42
43 for (auto& number : numbers)
44 ++number; // 编译错误,set/multiset中的元素是只读的
45 */
46 // 基于范围的for循环,无论循环体执行多少次,冒号后面的表达式永远只执行一次
47
48 for (auto score : scores())
49 cout << score << ' ';
50 cout << endl;
51
52 // 基于范围的for循环,其底层实现依然要借助于容器的迭代器,因
53 // 此任何可能导致迭代器失效的结构性改变,都将引发未定义的后果
54
55 auto ln = scores();
56 for (auto n : ln) {
57 cout << n << ' ';
58 // ln.pop_front(); // 因结构性改变而致迭代器失效
59 }
60 cout << endl;
61
62 return 0;
63}
xxxxxxxxxx
611// for3.cpp
2
3// 使自定义类型支持基于范围的for循环
4
5
6
7using namespace std;
8
9// 一个类只要提供了分别用于获取起始和终止迭代器的
10// begin和end方法,就可以支持基于范围的for循环
11
12template<typename T, size_t S>
13class Array {
14public:
15 T& operator[](size_t i) {
16 return arr[i];
17 }
18
19 T const& operator[](size_t i) const {
20 return const_cast<Array&>(*this)[i];
21 }
22
23 // 获取起始迭代器
24
25 T* begin(void) {
26 return arr;
27 }
28
29 T const* begin(void) const {
30 return const_cast<Array&>(*this).begin();
31 }
32
33 // 获取终止迭代器
34
35 T* end(void) {
36 return arr + S;
37 }
38
39 T const* end(void) const {
40 return const_cast<Array&>(*this).end();
41 }
42
43private:
44 T arr[S];
45};
46
47int main(void) {
48 int n = 0;
49 Array<decltype(n), 5> a1;
50
51 for (auto& elem : a1) // elem:int&
52 elem = ++n * 10;
53
54 auto const& a2 = a1;
55
56 for (auto& elem : a2) // elem:int const&
57 cout << elem << ' ';
58 cout << endl;
59
60 return 0;
61}
xxxxxxxxxx
1011// function1.cpp
2
3// 可调用对象与函数对象
4
5
6
7
8using namespace std;
9
10// 函数
11
12int fun(int x) {
13 cout << __FUNCTION__ << '(' << x << ")->" << flush;
14
15 return x;
16}
17
18// 实现了函数操作符的类
19
20class Foo {
21public:
22 int operator()(int x, int y) const {
23 cout << __FUNCTION__ << '(' << x << ',' << y << ")->" << flush;
24
25 return x + y;
26 }
27};
28
29// 可被转换为函数指针的类
30
31class Bar {
32 using hum_t = int (*)(int,int,int);
33
34public:
35 operator hum_t(void) const {
36 return hum;
37 }
38
39private:
40 static int hum(int x, int y, int z) {
41 cout << __FUNCTION__ << '(' << x << ',' << y << ',' << z << ")->" << flush;
42
43 return x + y + z;
44 }
45};
46
47// 用函数对象实现回调
48
49int run(function<int (int)> const& callback, int x) {
50 return callback(x);
51}
52
53int run(function<int (int,int)> const& callback, int x, int y) {
54 return callback(x, y);
55}
56
57int run(function<int (int,int,int)> const& callback, int x, int y, int z) {
58 return callback(x, y, z);
59}
60
61int main(void) {
62 // 能够被当做函数调用的不一定就是函数,它们也可能是:
63
64 // 1.存放函数入口地址的函数指针
65
66 int (*pfun)(int) = fun;
67 cout << pfun(10) << endl;
68
69 // 2.实现了函数操作符的类对象,亦称仿函数
70
71 Foo foo;
72 cout << foo(20, 30) << endl;
73
74 // 3.可被转换为函数指针的类对象
75
76 Bar bar;
77 cout << bar(40, 50, 60) << endl;
78
79 // 象pfun、foo、bar这样的对象被称为可调用对象,而它们
80 // 的类型:int(*)(int)、Foo、Bar,则被称为可调用类型
81
82 // function是可调用对象的包装器。它是一个类模板,可容纳
83 // 以上三种中的任何一种可调用对象,并按照函数语法调用它们
84
85 function<int (int)> ffun = fun;
86 cout << ffun(10) << endl;
87
88 function<int (int,int)> ffoo = foo;
89 cout << ffoo(20, 30) << endl;
90
91 function<int (int,int,int)> fbar = bar;
92 cout << fbar(40, 50, 60) << endl;
93
94 // 用函数对象实现回调
95
96 cout << run(fun, 10) << endl;
97 cout << run(foo, 20, 30) << endl;
98 cout << run(bar, 40, 50, 60) << endl;
99
100 return 0;
101}
xxxxxxxxxx
661// bind1.cpp
2
3// 函数绑定器
4
5
6
7
8using namespace std;
9
10// 函数
11
12int fun(int x) {
13 cout << __FUNCTION__ << '(' << x << ")->" << flush;
14
15 return x;
16}
17
18// 实现了函数操作符的类
19
20class Foo {
21public:
22 int operator()(int x, int y) const {
23 cout << __FUNCTION__ << '(' << x << ',' << y << ")->" << flush;
24
25 return x + y;
26 }
27};
28
29// 可被转换为函数指针的类
30
31class Bar {
32 using hum_t = int (*)(int,int,int);
33
34public:
35 operator hum_t(void) const {
36 return hum;
37 }
38
39private:
40 static int hum(int x, int y, int z) {
41 cout << __FUNCTION__ << '(' << x << ',' << y << ',' << z << ")->" << flush;
42
43 return x + y + z;
44 }
45};
46
47int main (void) {
48 // 绑定器可将任何可调用对象和需要传递给它们的参数绑定为一个函数对象。该函
49 // 数对象负责调用被绑定的可调用对象,依次传入被绑定的参数,并返回其返回值
50
51 function<int (void)> f1 = bind(fun, 10);
52 cout << f1() << endl;
53
54 // placeholders::_n是一个占位符,其值将由传给函数对象的第n个参数取代
55
56 Foo foo;
57 auto f2 = bind(foo, 20, placeholders::_1);
58 cout << f2(30) << endl;
59
60 // 第1和第4个参数,即80和20,在调用时被吞掉。第2和第3个
61 // 参数,即60和40,则作为第3和第1个参数被传给可调用对象
62
63 cout << bind(Bar(), placeholders::_3, 50, placeholders::_2)(80, 60, 40, 20) << endl;
64
65 return 0;
66}
xxxxxxxxxx
431// bind2.cpp
2
3// 绑定类的成员函数
4
5
6
7
8using namespace std;
9
10class A {
11public:
12 // 普通成员函数
13
14 int foo(/* A const* this, */int arg) const {
15 return /* this-> */var + arg;
16 }
17
18 // 静态成员函数
19
20 static int bar(int arg) {
21 return sta + arg;
22 }
23
24private:
25 int var = 10;
26 static int const sta = 20;
27};
28
29int main(void) {
30 A a;
31
32 // 绑定普通成员函数,注意作为this指针实参的调用对象地址
33
34 function<int (int)> ffoo = bind(&A::foo, &a, placeholders::_1);
35 cout << ffoo(1) << endl;
36
37 // 绑定静态成员函数,除多了作用域限定与全局函数没有区别
38
39 function<int (int)> fbar = bind(A::bar, placeholders::_1);
40 cout << fbar(2) << endl;
41
42 return 0;
43}
xxxxxxxxxx
421// bind3.cpp
2
3// 新版本的bind简化和强化了老版本的bind1st和bind2nd
4
5
6
7
8
9
10using namespace std;
11
12int main(void) {
13 vector<int> scores{70, 40, 80, 50, 70, 80, 60, 60, 90, 50};
14 auto begin = scores.begin(), end = scores.end();
15
16 // 老版本的bind1st和bind2nd只能对带两个参数的函数绑定其第
17 // 一或第二个参数,其目的就是将一个二元函数降级为一元函数
18
19 // 60 <= score
20 cout << "及格人数:" << count_if(begin, end, bind1st(less_equal<int>(), 60)) << endl;
21
22 // score < 60
23 cout << "不及格人数:" << count_if(begin, end, bind2nd(less<int>(), 60)) << endl;
24
25 // 新版本的bind对被绑定函数的参数个数和具体绑定哪些参数都不做任何限制,更加灵活、通用且形式统一
26
27 using placeholders::_1;
28
29 // 60 <= score
30 cout << "及格人数:" << count_if(begin, end, bind(less_equal<int>(), 60, _1)) << endl;
31
32 // score < 60
33 cout << "不及格人数:" << count_if(begin, end, bind(less<int>(), _1, 60)) << endl;
34
35 // 通过bind还可以组合多个函数构成复合闭包
36
37 // 70 <= score < 90
38 cout << "良好人数:" << count_if(begin, end, bind(logical_and<bool>(),
39 bind(less_equal<int>(), 70, _1), bind(less<int>(), _1, 90))) << endl;
40
41 return 0;
42}
lambda表达式定义了一个匿名函数,其本质是一个匿名的仿函数对象,亦可被视为第4种形式的可调用对象。
xxxxxxxxxx
421// lambda1.cpp
2
3// lambda表达式
4
5
6
7
8using namespace std;
9
10int main(void) {
11 // [捕获表](参数表) 选项 -> 返回类型 { 函数体 }
12
13 auto f1 = [](int x) -> int { return x * x; };
14
15 // lambda表达式的值是一个实现了函数操作符的类对象,即仿函数。该类的成员变量来自
16 // 于捕获表,其函数操作符函数的参数、返回类型和函数体均来自于lambda表达式的定义
17
18 cout << f1(10) << endl; // 100
19
20 // 返回类型通常可以省略,编译器可以根据return语句自动推导出返回类型
21
22 auto f2 = [](int x) { return x * x; };
23
24 cout << f2(11) << endl; // 121
25
26 // 列表初始化不能用于返回类型的自动推导
27
28 // auto f3 = [](void) { return {10, 20, 30, 40, 50}; };
29 auto f3 = [](void) -> vector<int> { return {10, 20, 30, 40, 50}; };
30
31 for (auto n : f3())
32 cout << n << ' ';
33 cout << endl; // 10 20 30 40 50
34
35 // 空参数表和返回类型可以省略
36
37 [](void) -> void { cout << "hello world" << endl; }(); // hello world
38 []() { cout << "hello world" << endl; }(); // hello world
39 [] { cout << "hello world" << endl; }(); // hello world
40
41 return 0;
42}
xxxxxxxxxx
1641// lambda2.cpp
2
3// lambda表达式的捕获表
4
5
6
7
8using namespace std;
9
10int a = 10;
11
12class Base {
13protected:
14 int b = 20;
15};
16
17class Derived : public Base {
18public:
19 void foo(int d) {
20 // 不捕获任何外部变量
21
22 [](int e) {
23 ++a;
24 cout << "a=" << a << endl;
25 // ++b;
26 // cout << "b=" << b << endl;
27 // ++c;
28 // cout << "c=" << c << endl;
29 // ++d;
30 // cout << "d=" << d << endl;
31 ++e;
32 cout << "e=" << e << endl << endl; }(50);
33
34 // 按值捕获指定的外部变量
35
36 [d](int e) {
37 ++a;
38 cout << "a=" << a << endl;
39 // ++b;
40 // cout << "b=" << b << endl;
41 // ++c;
42 // cout << "c=" << c << endl;
43 // ++d; // 不可修改按值捕获的外部变量
44 cout << "d=" << d << endl;
45 ++e;
46 cout << "e=" << e << endl << endl; }(50);
47
48 // 按引用捕获指定的外部变量
49
50 [&d](int e) {
51 ++a;
52 cout << "a=" << a << endl;
53 // ++b;
54 // cout << "b=" << b << endl;
55 // ++c;
56 // cout << "c=" << c << endl;
57 ++d; // 可修改按引用捕获的外部变量
58 cout << "d=" << d << endl;
59 ++e;
60 cout << "e=" << e << endl << endl; }(50);
61
62 // 捕获this指针
63
64 [this](int e) {
65 ++a;
66 cout << "a=" << a << endl;
67 ++b;
68 cout << "b=" << b << endl;
69 ++c;
70 cout << "c=" << c << endl;
71 // ++d
72 // cout << "d=" << d << endl;
73 ++e;
74 cout << "e=" << e << endl << endl; }(50);
75
76 // 按值捕获所有外部变量(包括this指针)
77
78 [=](int e) {
79 ++a;
80 cout << "a=" << a << endl;
81 ++b;
82 cout << "b=" << b << endl;
83 ++c;
84 cout << "c=" << c << endl;
85 // ++d; // 不可修改按值捕获的外部变量
86 cout << "d=" << d << endl;
87 ++e;
88 cout << "e=" << e << endl << endl; }(50);
89
90 // 按引用捕获所有外部变量(包括this指针)
91
92 [&](int e) {
93 ++a;
94 cout << "a=" << a << endl;
95 ++b;
96 cout << "b=" << b << endl;
97 ++c;
98 cout << "c=" << c << endl;
99 ++d; // 可修改按引用捕获的外部变量
100 cout << "d=" << d << endl;
101 ++e;
102 cout << "e=" << e << endl << endl; }(50);
103
104 // 按值捕获所有外部变量(包括this指针),按引用捕获指定的外部变量
105
106 [=, &d](int e) {
107 ++a;
108 cout << "a=" << a << endl;
109 ++b;
110 cout << "b=" << b << endl;
111 ++c;
112 cout << "c=" << c << endl;
113 ++d; // 可修改按引用捕获的外部变量
114 cout << "d=" << d << endl;
115 ++e;
116 cout << "e=" << e << endl << endl; }(50);
117 }
118
119private:
120 int c = 30;
121};
122
123int main (void) {
124 Derived d;
125 d.foo(40);
126
127 // 按值捕获,保存在f1中的是x自增之前的值60
128
129 int x = 60;
130 auto f1 = [x] { cout << "x=" << x << endl << endl; };
131 ++x;
132 f1();
133
134 // 按引用捕获,保存在f2中的是y的引用,自增后变成71
135
136 int y = 70;
137 auto f2 = [&y]{ cout << "y=" << y << endl << endl; };
138 ++y;
139 f2();
140
141 // 非可变lambda表达式不能修改按值捕获的外部变量
142
143 int z = 80;
144 [=] { cout << "z=" << /*++*/z << endl << endl; }();
145
146 // 带有mutable关键字的可变lambda表达式可以修改按值捕获的外部变量,但实际被修改的
147 // 只是该变量在lambda表达式中的拷贝。可变lambda表达式不可省略参数表,即使其为空
148
149 [=]() mutable { cout << "z=" << ++z << endl; }();
150 cout << "z=" << z << endl << endl;
151
152 // 这与按引用捕获外部变量并在lambda表达式中修改的情况不一样
153
154 [&] { cout << "z=" << ++z << endl; }();
155 cout << "z=" << z << endl << endl;
156
157 // 不捕获任何外部变量的lambda表达式可被隐式转换为相应类型的函数指针
158
159 double (*pyth)(double, double) =
160 [](double a, double b) -> double { return sqrt(a * a + b * b); };
161 cout << "c=" << pyth(3, 4) << endl;
162
163 return 0;
164}
xxxxxxxxxx
831// lambda3.cpp
2
3// 利用lambda表达式简化标准库算法的调用
4
5
6
7
8
9
10
11using namespace std;
12
13class Student {
14public:
15 Student(string const& name, int age, int score) : name(name), age(age), score(score) {}
16
17 friend ostream& operator<<(ostream& os, Student const& student) {
18 return os << '(' << student.name << ',' << student.age << ',' << student.score << ')';
19 }
20
21 string name; // 姓名
22 int age; // 年龄
23 int score; // 成绩
24};
25
26int main (void) {
27 vector<Student> vs{
28 {"张飞", 40, 80},
29 {"赵云", 30, 70},
30 {"关羽", 30, 80},
31 {"黄忠", 30, 90},
32 {"马超", 20, 80}};
33
34 copy(vs.begin(), vs.end(), ostream_iterator<Student>(cout, ""));
35 cout << endl;
36
37 // 用仿函数做排序比较器
38 /*
39 class StudentComparator {
40 public:
41 // 按成绩降序排列,成绩相同者按年龄升序排列
42 bool operator()(Student const& a, Student const& b) const {
43 if (a.score == b.score)
44 return a.age < b.age;
45 else
46 return a.score > b.score;
47 }
48 };
49
50 sort(vs.begin(), vs.end(), StudentComparator());
51 */
52 // 用lambda表达式做排序比较器
53
54 sort(vs.begin(), vs.end(),
55 [](Student const& a, Student const& b) {
56 if (a.score == b.score)
57 return a.age < b.age;
58 else
59 return a.score > b.score;
60 });
61
62 copy(vs.begin(), vs.end(), ostream_iterator<Student>(cout, ""));
63 cout << endl;
64
65 vector<int> scores{70, 40, 80, 50, 70, 80, 60, 60, 90, 50};
66 auto begin = scores.begin(), end = scores.end();
67
68 // 通过bind组合多个函数构成复合闭包
69 /*
70 using placeholders::_1;
71
72 // 70 <= score < 90
73 cout << "良好人数:" << count_if(begin, end, bind(logical_and<bool>(),
74 bind(less_equal<int>(), 70, _1), bind(less<int>(), _1, 90))) << endl;
75 */
76 // 使用lambda表达式构造闭包更加简洁
77
78 // 70 <= score < 90
79 cout << "良好人数:" << count_if(begin, end,
80 [](int score) { return 70 <= score && score < 90; }) << endl;
81
82 return 0;
83}
tuple可以理解为是对老版本pair的增强和扩展,其中的元素个数不再限于两个,功能也更加丰富。
xxxxxxxxxx
671// tuple1.cpp
2
3// 泛型元组
4
5
6
7
8using namespace std;
9
10int main (void) {
11 char const* name = "张飞";
12 int age = 25;
13 double height = 1.75;
14
15 // 直接构造tuple对象
16
17 tuple<char const*, int, double> t1(name, age, height);
18
19 // 获取tuple元素的值
20
21 cout << '(' << get<0>(t1) << ',' << get<1>(t1) << ',' << get<2>(t1) << ')' << endl;
22
23 // 通过make_tuple构造tuple对象
24
25 auto t2 = make_tuple(name, age, height);
26 cout << '(' << get<0>(t2) << ',' << get<1>(t2) << ',' << get<2>(t2) << ')' << endl;
27
28 // 按以上两种方式构造的tuple对象所保存的只是构造实参的拷贝
29
30 get<0>(t1) = "赵云";
31 get<1>(t2) = 20;
32 cout << '(' << name << ',' << age << ',' << height << ')' << endl;
33
34 // 通过tie构造tuple对象,保存构造实参的左值引用
35
36 auto t3 = tie(name, age, height);
37 get<2>(t3) = 1.65;
38 cout << '(' << name << ',' << age << ',' << height << ')' << endl;
39
40 // 事实上tie的本意是用于解析而非构造tuple对象
41
42 auto t4 = make_tuple("关羽", 30, 1.85);
43 tie(name, age, height) = t4;
44 cout << '(' << name << ',' << age << ',' << height << ')' << endl;
45
46 // 可以用ignore占位符忽略掉不感兴趣的元素
47
48 auto t5 = make_tuple("马超", 22, 1.65);
49 tie(name, ignore, height) = t5;
50 cout << '(' << name << ',' << age << ',' << height << ')' << endl;
51
52 // 通过forward_as_tuple构造tuple对象,保存构造实参的右值引用
53
54 auto t6 = forward_as_tuple("黄忠", 40, 1.95);
55 cout << '(' << get<0>(t6) << ',' << get<1>(t6) << ',' << get<2>(t6) << ')' << endl;
56
57 // 用tuple_cat连接多个tuple对象
58
59 int x = 10, y = 20;
60 auto t7 = tuple_cat(make_tuple(x, y), tie(x, y), forward_as_tuple(x, y));
61 ++x; ++y;
62 cout << "((" << get<0>(t7) << ',' << get<1>(t7) << "),(" <<
63 get<2>(t7)++ << ',' << get<3>(t7)++ << "),(" <<
64 get<4>(t7) << ',' << get<5>(t7) << "))" << endl;
65
66 return 0;
67}
xxxxxxxxxx
491// rvr1.cpp
2
3// 左值和右值
4
5
6
7using namespace std;
8
9int& foo(int& a) {
10 return a;
11}
12
13int bar(int& a) {
14 return a;
15}
16
17string hum(void) {
18 return "hello world";
19}
20
21int main(void) {
22 // 区分左右值,关键看是否可对该值取地址
23
24 int a = 1, b = 2;
25
26 // 可以取地址的值就是左值,左值通常具名
27
28 cout << &a << endl; // 有名变量
29 cout << &foo(a) << endl; // 引用形式的函数返回值
30 cout << &++a << endl; // 前缀自增减表达式的值
31 cout << &(a = b) << endl; // 赋值类表达式的值
32
33 // 不可取地址的值就是右值,右值通常匿名
34
35 // cout << &10 << endl; // 字面值常量
36 // cout << &bar(a) << endl; // 值形式的函数返回值
37 // cout << &a++ << endl; // 后缀自增减表达式的值
38 // cout << &(a + b) << endl; // 运算表达式的值
39 // cout << &(double)a << endl; // 类型转换表达式的值
40
41 // 以上右值也被称为纯右值,即临时值,天然具有只读属性,但
42 // 类对象形式的临时值,虽为右值,在某些编译器上亦可取地址
43
44 // cout << &hum() << endl;
45 // cout << &(string)"Hello, World !" << endl;
46 // cout << &[=] { return a + b; } << endl;
47
48 return 0;
49}
xxxxxxxxxx
611// rvr2.cpp
2
3// 左值引用和右值引用
4
5
6
7using namespace std;
8
9class X {
10public:
11 X(void) {
12 cout << "构造:" << this << endl;
13 }
14
15 X(X const& x) {
16 cout << "拷贝:" << &x << "->" << this << endl;
17 }
18
19 ~X(void) {
20 cout << "析构:" << this << endl;
21 }
22};
23
24X foo(void) {
25 X x; // 局部值
26
27 return x;
28}
29
30int main(void) {
31 int a = 1, b = 2;
32
33 // 左值引用只能引用左值,不能引用右值
34
35 int& lvr1 = a;
36 // int& lvr2 = a + b;
37
38 // 右值引用只能引用右值,不能引用左值
39
40 int&& rvr1 = a + b;
41 // int&& rvr2 = a;
42
43 // 常左值引用既能引用左值,也能引用右值,故称万能引用
44
45 int const& clvr1 = a;
46 int const& clvr2 = a + b;
47
48 // 临时值仅具语句级生命期
49
50 foo(); // 构造(局部值)->拷贝(临时值)->析构(局部值)->析构(临时值)
51 cout << "--------------------" << endl;
52
53 // 引用可将临时值的寿命延长至与引用变量本身一样
54
55 X&& rvr3 = foo(); // 构造(局部值)->拷贝(临时值)->析构(局部值)
56 cout << "--------------------" << endl;
57
58 return 0;
59} // 析构(临时值)
60
61// g++ -fno-elide-constructors rvr2.cpp
xxxxxxxxxx
491// rvr3.cpp
2
3// 通用引用
4
5
6
7using namespace std;
8
9// 在函数模板隐式推断过程中,若实参为左值,则T&&被推断为左值引用,
10// 若实参为右值,则T&&被推断为右值引用,这样的引用被称为通用引用
11
12template<typename T>
13void foo(T&& r) {
14 cout << r << endl;
15}
16
17// 只有T&&才是通用引用,加了const就不是了
18
19template<typename T>
20void bar(T const&& r) {
21 cout << r << endl;
22}
23
24int main(void) {
25 int a = 1, b = 2;
26
27 foo(a); // r:int&,左值引用可以引用左值
28 foo(a + b); // r:int&&,右值引用可以引用右值
29
30 // 不做隐式推断,没有通用引用
31
32 // foo<int>(a); // r:int&&,右值引用无法引用左值
33 foo<int>(a + b); // r:int&&,右值引用可以引用右值
34
35 // T const&&只能被推断为常右值引用
36
37 // bar(a); // r:int const&&,右值引用无法引用左值
38 bar(a + b); // r:int const&&,右值引用可以引用右值
39
40 // 类似的规则也同样适用于基于auto关键字的类型推导
41
42 auto&& c = a; // c:int&,左值引用可以引用左值
43 auto&& d = a + b; // d:int&&,右值引用可以引用右值
44
45 // auto const&& e = a; // e:int const&&,右值引用无法引用左值
46 auto const&& f = a + b; // f:int const&&,右值引用可以引用右值
47
48 return 0;
49}
C++98/03标准不允许声明引用的引用,但C++11允许这么声明,并根据引用折叠规则将其处理为简单引用的形式:只有右值引用的右值引用还是右值引用,其它情况下的叠加都是左值引用。
xxxxxxxxxx
341// rvr4.cpp
2
3// 引用折叠
4
5
6
7using namespace std;
8
9template<typename T>
10void what(void) {
11 if (is_lvalue_reference<T>::value)
12 cout << "左值引用" << endl;
13 else
14 if (is_rvalue_reference<T>::value)
15 cout << "右值引用" << endl;
16 else
17 cout << "不是引用" << endl;
18}
19
20int main(void) {
21 using lvr_t = int&;
22 using rvr_t = int&&;
23
24 what<lvr_t>(); // 左值引用
25 what<rvr_t>(); // 右值引用
26
27 what<lvr_t&>(); // 左值引用的左值引用是左值引用
28 what<rvr_t&>(); // 右值引用的左值引用是左值引用
29
30 what<lvr_t&&>(); // 左值引用的右值引用是左值引用
31 what<rvr_t&&>(); // 右值引用的右值引用是右值引用
32
33 return 0;
34}
xxxxxxxxxx
661// rvr5.cpp
2
3// move和forward
4
5
6
7using namespace std;
8
9void foo(int& lvr) {
10 cout << "foo(int&)" << endl;
11}
12
13void foo(int&& rvr) {
14 cout << "foo(int&&)" << endl;
15}
16
17template<typename T>
18void bar(T&& r) {
19 foo(r); // 无论r是左值引用还是右值引用,其实都是左值
20}
21
22template<typename T>
23void hum(T&& r) {
24 foo(move(r)); // 无论r是左值引用还是右值引用,一律被move处理为右值
25}
26
27template<typename T>
28void fun(T&& r) {
29 foo(forward<T>(r)); // r是左值或右值引用,被forward处理为左值或右值
30}
31
32int main(void) {
33 int a = 1, b = 2;
34
35 // 右值引用只能引用右值,但其本身是左值,可取地址,可被
36 // 修改,可被左值引用引用
37
38 int&& c = a + b;
39 cout << &c << endl;
40 cout << ++c << endl;
41 int& d = c;
42
43 // 左值引用只能引用左值,其本身也是左值,可取地址,可被
44 // 修改,不能被右值引用引用,除非通过move将其转换为右值
45
46 int& e = a;
47 cout << &e << endl;
48 cout << ++e << endl;
49 // int&& f = e;
50 int&& g = move(e);
51 int&& h = move(a);
52
53 foo(a); // ->foo(int&)
54 foo(a + b); // ->foo(int&&)
55
56 bar(a); // ->foo(int&)
57 bar(a + b); // ->foo(int&)
58
59 hum(a); // ->foo(int&&)
60 hum(a + b); // ->foo(int&&)
61
62 fun(a); // ->foo(int&)
63 fun(a + b); // ->foo(int&&)
64
65 return 0;
66}
xxxxxxxxxx
541// move1.cpp
2
3// 支持浅拷贝的构造函数
4
5
6
7
8
9using namespace std;
10
11class String {
12public:
13 String(char const* s)
14 : s(strcpy(new char[strlen(s ? s : "")+1], s ? s : "")) {
15 cout << "构造函数:" << this << endl;
16 }
17
18 // 支持浅拷贝的构造函数
19
20 String(String const& str) : s(str.s) {
21 cout << "浅拷构造:" << &str << "->" << this << endl;
22 }
23
24 ~String(void) {
25 cout << "析构函数:" << this << endl;
26
27 delete[] s;
28 }
29
30 friend ostream& operator<< (ostream& os, String const& str) {
31 return os << str.s;
32 }
33
34private:
35 char* s;
36};
37
38String foo(void) {
39 String str = "hello world";
40
41 cout << "foo: " << str << endl;
42
43 return str;
44}
45
46int main(void) {
47 String str = foo();
48
49 cout << "main: " << str << endl; // 运行错误
50
51 return 0;
52} // 崩溃
53
54// g++ -fno-elide-constructors move1.cpp
xxxxxxxxxx
551// move2.cpp
2
3// 支持深拷贝的构造函数
4
5
6
7
8
9using namespace std;
10
11class String {
12public:
13 String(char const* s)
14 : s(strcpy(new char[strlen(s ? s : "")+1], s ? s : "")) {
15 cout << "构造函数:" << this << endl;
16 }
17
18 // 支持深拷贝的构造函数
19
20 String(String const& str)
21 : s(strcpy(new char[strlen(str.s)+1], str.s)) {
22 cout << "深拷构造:" << &str << "->" << this << endl;
23 }
24
25 ~String(void) {
26 cout << "析构函数:" << this << endl;
27
28 delete[] s;
29 }
30
31 friend ostream& operator<< (ostream& os, String const& str) {
32 return os << str.s;
33 }
34
35private:
36 char* s;
37};
38
39String foo(void) {
40 String str = "hello world";
41
42 cout << "foo: " << str << endl;
43
44 return str;
45}
46
47int main(void) {
48 String str = foo();
49
50 cout << "main: " << str << endl;
51
52 return 0;
53}
54
55// g++ -fno-elide-constructors move2.cpp
xxxxxxxxxx
561// move3.cpp
2
3// 支持移动语义的构造函数
4
5
6
7
8
9using namespace std;
10
11class String {
12public:
13 String(char const* s)
14 : s(strcpy(new char[strlen(s ? s : "")+1], s ? s : "")) {
15 cout << "构造函数:" << this << endl;
16 }
17
18 // 支持移动语义的构造函数
19
20 String(String&& str) : s(str.s) {
21 cout << "移动构造:" << &str << "->" << this << endl;
22
23 str.s = nullptr;
24 }
25
26 ~String(void) {
27 cout << "析构函数:" << this << endl;
28
29 delete[] s;
30 }
31
32 friend ostream& operator<< (ostream& os, String const& str) {
33 return os << str.s;
34 }
35
36private:
37 char* s;
38};
39
40String foo(void) {
41 String str = "hello world";
42
43 cout << "foo: " << str << endl;
44
45 return str;
46}
47
48int main(void) {
49 String str = foo(); // 等号右边的对象是一个将亡右值,其资源即将被移动到左侧对象中
50
51 cout << "main: " << str << endl;
52
53 return 0;
54}
55
56// g++ -fno-elide-constructors move3.cpp
同时提供支持深拷贝和移动语义的构造函数和赋值操作符函数,编译器会在适当的时候选择适当的版本,在保证功能的同时提高性能。
xxxxxxxxxx
1091// move4.cpp
2
3// 同时提供支持深拷贝和移动语义的构造函数和赋值操作符函数
4
5
6
7
8
9using namespace std;
10
11class String {
12public:
13 String(char const* s)
14 : s(strcpy(new char[strlen(s ? s : "")+1], s ? s : "")) {
15 cout << "构造函数:" << this << endl;
16 }
17
18 // 支持深拷贝的构造函数
19
20 String(String const& str)
21 : s(strcpy(new char[strlen(str.s)+1], str.s)) {
22 cout << "深拷构造:" << &str << "->" << this << endl;
23 }
24
25 // 支持深拷贝的赋值操作符函数
26
27 String& operator=(String const& str) {
28 cout << "深拷赋值:" << &str << "->" << this << endl;
29
30 if (&str != this) {
31 String tmp = str; // 深拷构造
32 swap(s, tmp.s);
33 }
34
35 return *this;
36 }
37
38 // 支持移动语义的构造函数
39
40 String(String&& str) : s(str.s) {
41 cout << "移动构造:" << &str << "->" << this << endl;
42
43 str.s = nullptr;
44 }
45
46 // 支持移动语义的赋值操作符函数
47
48 String& operator=(String&& str) {
49 cout << "移动赋值:" << &str << "->" << this << endl;
50
51 if (&str != this) {
52 String tmp = move(str); // 移动构造
53 swap(s, tmp.s);
54 }
55
56 return *this;
57 }
58
59 ~String(void) {
60 cout << "析构函数:" << this << endl;
61
62 delete[] s;
63 }
64
65 friend ostream& operator<< (ostream& os, String const& str) {
66 return os << str.s;
67 }
68
69private:
70 char* s;
71};
72
73String foo(void) {
74 String str = "hello world";
75
76 cout << "foo: " << str << endl;
77
78 return str;
79}
80
81int main(void) {
82 String a = "hello tarena", b = "hello C++";
83
84 cout << "---------------------------------------- 1" << endl;
85
86 String c = a; // 深拷构造
87 cout << "main: " << c << endl;
88
89 cout << "---------------------------------------- 2" << endl;
90
91 c = b; // 深拷赋值
92 cout << "main: " << c << endl;
93
94 cout << "---------------------------------------- 3" << endl;
95
96 String d = foo(); // 移动构造
97 cout << "main: " << d << endl;
98
99 cout << "---------------------------------------- 4" << endl;
100
101 c = foo(); // 移动赋值
102 cout << "main: " << c << endl;
103
104 cout << "---------------------------------------- 5" << endl;
105
106 return 0;
107}
108
109// g++ -fno-elide-constructors move4.cpp
几乎所有标准库容器都提供了类似emplace_back、emplace_front和emplace这样的接口,以作为传统的push_back、push_front和insert接口的替代方案。相较于后者,前者采用在容器内部就地构造对象的方式,以尽可能避免过多的内存复制和移动,具有更好的运行时性能。
xxxxxxxxxx
851// emplace1.cpp
2
3// 就地构造
4
5
6
7
8
9
10using namespace std;
11
12class Point2D {
13public:
14 Point2D(int x, int y) : x(x), y(y) {
15 cout << "构造函数:" << this << endl;
16 }
17
18 Point2D(Point2D const& p) : x(p.x), y(p.y) {
19 cout << "拷贝构造:" << &p << "->" << this << endl;
20 }
21
22 Point2D& operator=(Point2D const& p) {
23 cout << "拷贝赋值:" << &p << "->" << this << endl;
24
25 if (&p != this) {
26 x = p.x;
27 y = p.y;
28 }
29
30 return *this;
31 }
32
33 ~Point2D(void) {
34 cout << "析构函数:" << this << endl;
35 }
36
37 friend ostream& operator<<(ostream& os, Point2D const& p) {
38 return os << '(' << p.x << ',' << p.y << ')';
39 }
40
41private:
42 int x, y;
43};
44
45int main (void) {
46 vector<Point2D> v1;
47
48 v1.push_back({1, 2});
49
50 cout << "----------------------------------- 1" << endl;
51
52 v1.push_back({5, 6});
53
54 cout << "----------------------------------- 2" << endl;
55
56 v1.insert(v1.begin() + 1, {3, 4});
57
58 cout << "----------------------------------- 3" << endl;
59
60 copy(v1.begin(), v1.end(), ostream_iterator<Point2D>(cout, ""));
61 cout << endl;
62
63 cout << "----------------------------------- 4" << endl;
64
65 vector<Point2D> v2;
66
67 v2.emplace_back(1, 2);
68
69 cout << "----------------------------------- 5" << endl;
70
71 v2.emplace_back(5, 6);
72
73 cout << "----------------------------------- 6" << endl;
74
75 v2.emplace(v2.begin() + 1, 3, 4);
76
77 cout << "----------------------------------- 7" << endl;
78
79 copy(v2.begin(), v2.end(), ostream_iterator<Point2D>(cout, ""));
80 cout << endl;
81
82 cout << "----------------------------------- 8" << endl;
83
84 return 0;
85}
C++11在C++98/03所提供的四个基于红黑树的有序关联容器,map、multimap、set和multiset的基础上,又增加了四个基于散列表的无序关联容器,unordered_map、unordered_multimap、unordered_set和unordered_multiset。与前者相比,后者通过哈希而非排序组织其中的元素,因而效率更高。
xxxxxxxxxx
831// unordered1.cpp
2
3// 无序容器
4
5
6
7
8
9using namespace std;
10
11// 姓名类
12
13class Name {
14public:
15 Name(string const& firstName, string const& familyName)
16 : firstName(firstName), familyName(familyName) {}
17
18 string firstName, familyName;
19};
20
21// 哈希器
22
23class NameHash {
24public:
25 size_t operator()(Name const& name) const {
26 return hash<string>()(name.firstName) ^ (hash<string>()(name.familyName) << 1);
27 }
28};
29
30// 判等器
31
32class NameEqual {
33public:
34 bool operator()(Name const& a, Name const& b) const {
35 return a.firstName == b.firstName && a.familyName == b.familyName;
36 }
37};
38
39int main (void) {
40 // 缺省构造
41
42 unordered_map<string, int> a;
43
44 // 列表构造
45
46 unordered_map<string, int> b {{"张飞", 70}, {"赵云", 80}, {"关羽", 90}};
47
48 for (auto const& kv : b)
49 cout << kv.first << ':' << kv.second << endl;
50
51 // 拷贝构造
52
53 unordered_map<string, int> c = b;
54
55 for (auto const& kv : c)
56 cout << kv.first << ':' << kv.second << endl;
57
58 // 移动构造
59
60 unordered_map<string, int> d = move(c);
61
62 for (auto const& kv : d)
63 cout << kv.first << ':' << kv.second << endl;
64
65 // 范围构造
66
67 vector<pair<string, int>> e {{"张飞", 70}, {"赵云", 80}, {"关羽", 90}};
68 unordered_map<string, int> f(e.begin(), e.end());
69
70 for (auto const& kv : f)
71 cout << kv.first << ':' << kv.second << endl;
72
73 // 如果键的类型不是基本类型,那么必须在构造容
74 // 器的同时指定与键类型相适应的哈希器和判等器
75
76 unordered_map<Name, int, NameHash, NameEqual> g {
77 {{"飞", "张"}, 70}, {{"云", "赵"}, 80}, {{"羽", "关"}, 90}};
78
79 for (auto const& kv : g)
80 cout << kv.first.familyName << kv.first.firstName << ':' << kv.second << endl;
81
82 return 0;
83}
xxxxxxxxxx
241// constant1.cpp
2
3// C++98/03标准为类定义编译期常量的方法
4
5
6
7using namespace std;
8
9class One {
10public:
11 static int const value = 1;
12};
13
14class Two {
15public:
16 enum { value = 2 };
17};
18
19int main(void) {
20 cout << One::value << endl; // 1
21 cout << Two::value << endl; // 2
22
23 return 0;
24}
在C++11中,为一个类定义编译期常量,既无需自己定义常静态成员变量,亦无需提供枚举成员类型,只要从integral_constant基类继承即可。
xxxxxxxxxx
181// constant2.cpp
2
3// C++11标准为类定义编译期常量的方法
4
5
6
7using namespace std;
8
9class One : public integral_constant<int, 1> {};
10
11class Two : public integral_constant<int, 2> {};
12
13int main(void) {
14 cout << One::value << endl; // 1
15 cout << Two::value << endl; // 2
16
17 return 0;
18}
xxxxxxxxxx
391// constant3.cpp
2
3// integral_constant类模板的简化实现
4
5
6
7using namespace std;
8
9template<typename T, T v>
10class IntegralConstant {
11public:
12 typedef T value_type;
13 typedef IntegralConstant<value_type, v> type;
14
15 static value_type const value = v;
16
17 operator value_type(void) const {
18 return value;
19 }
20};
21
22class One : public IntegralConstant<int, 1> {};
23
24class Two : public IntegralConstant<int, 2> {};
25
26int main (void) {
27 cout << One::value << endl; // 1
28 cout << Two::value << endl; // 2
29
30 One one;
31 One::value_type a = one;
32 cout << a << endl; // 1
33
34 Two two;
35 Two::value_type b = two;
36 cout << b << endl; // 2
37
38 return 0;
39}
xxxxxxxxxx
351// constant4.cpp
2
3// 编译期布尔类型
4
5
6
7using namespace std;
8/*
9typedef integral_constant<bool, false> false_type;
10typedef integral_constant<bool, true> true_type;
11*/
12template<typename T> class IsPointer : public false_type {};
13template<typename T> class IsPointer<T*> : public true_type {};
14
15template<typename T> class IsReference : public false_type {};
16template<typename T> class IsReference<T&> : public true_type {};
17
18template<typename T> class IsArray : public false_type {};
19template<typename T> class IsArray<T[]> : public true_type {};
20
21int main(void) {
22 cout << boolalpha << false_type::value << endl; // false
23 cout << true_type::value << endl; // true
24
25 cout << IsPointer<int>::value << endl; // false
26 cout << IsPointer<int*>::value << endl; // true
27
28 cout << IsReference<int>::value << endl; // false
29 cout << IsReference<int&>::value << endl; // true
30
31 cout << IsArray<int>::value << endl; // false
32 cout << IsArray<int[]>::value << endl; // true
33
34 return 0;
35}
当且仅当实例化模板的类型实参为... | ...模板实例化类中的布尔型静态成员value的值为true |
---|---|
空类型 | is_void |
整数类型 | is_integral |
浮点数类型 | is_floating_point |
指针类型(不包括成员指针) | is_pointer |
成员指针类型 | is_member_pointer |
引用类型 | is_reference |
数组类型 | is_array |
枚举类型 | is_enum |
联合类型 | is_union |
类类型(包括结构体) | is_class |
多态类型(含虚函数) | is_polymorphic |
抽象类型(含纯虚函数) | is_abstract |
函数类型 | is_function |
算术类型(整数、浮点数) | is_arithmetic |
基本类型(空、整数、浮点数、指针) | is_fundamental |
复合类型 | is_compound |
对象类型(除空、引用、函数外) | is_object |
标量类型(空、指针、成员指针、枚举、算术) | is_scalar |
有符号类型 | is_signed |
无符号类型 | is_unsigned |
常类型 | is_const |
······ | ······ |
xxxxxxxxxx
341// is1.cpp
2
3// 编译期类型判断
4
5
6
7using namespace std;
8
9int main(void) {
10 cout << boolalpha;
11
12 cout << is_function<int (int,int)>::value << endl; // true
13
14 cout << is_const<int>::value << endl; // false
15 cout << is_const<const int>::value << endl; // true
16 cout << is_const<int const>::value << endl; // true
17
18 cout << is_const<int*>::value << endl; // false
19 cout << is_const<const int*>::value << endl; // false
20 cout << is_const<int const*>::value << endl; // false
21 cout << is_const<int* const>::value << endl; // true
22 cout << is_const<int const* const>::value << endl; // true
23
24 cout << is_const<int&>::value << endl; // false
25 cout << is_const<const int&>::value << endl; // false
26 cout << is_const<int const&>::value << endl; // false
27
28 // 禁止针对引用本身而非其目标使用常限定
29
30 // cout << is_const<int& const>::value << endl;
31 // cout << is_const<int const& const>::value << endl;
32
33 return 0;
34}
当且仅当实例化模板的两个类型实参满足... | ...模板实例化类中的布尔型静态成员value的值为true |
---|---|
相同类型 | is_same |
第一个是第二个的基类 | is_base_of |
第一个能被隐式转换为第二个 | is_convertible |
······ | ······ |
xxxxxxxxxx
571// is2.cpp
2
3// 编译期类型关系判断
4
5
6
7using namespace std;
8
9class A {}; // A
10class B : public A {}; // /
11 // B C
12class C {}; // \ /
13class D : public B, public C {}; // D
14
15class Integer {
16public:
17 // int -显式转换-> Integer
18
19 explicit Integer(int n = 0) : n(n) {}
20
21 // Integer -隐式转换-> int
22
23 operator int(void) const {
24 return n;
25 }
26
27private:
28 int n;
29};
30
31int main (void) {
32 cout << boolalpha;
33
34 cout << is_same<signed int, int>::value << endl; // true
35 cout << is_same<int, unsigned int>::value << endl; // false
36 cout << is_same<unsigned long, size_t>::value << endl; // true
37
38 cout << is_base_of<A, B>::value << endl; // true
39 cout << is_base_of<A, C>::value << endl; // false
40 cout << is_base_of<A, D>::value << endl; // true
41
42 cout << is_convertible<double, int>::value << endl; // true
43 cout << is_convertible<double*, int*>::value << endl; // false
44 cout << is_convertible<int*, void*>::value << endl; // true
45
46 cout << is_convertible<A, B>::value << endl; // false
47 cout << is_convertible<B, A>::value << endl; // true
48 cout << is_convertible<A*, B*>::value << endl; // false
49 cout << is_convertible<B*, A*>::value << endl; // true
50 cout << is_convertible<A&, B&>::value << endl; // false
51 cout << is_convertible<B&, A&>::value << endl; // true
52
53 cout << is_convertible<int, Integer>::value << endl; // false
54 cout << is_convertible<Integer, int>::value << endl; // true
55
56 return 0;
57}
用特定类型实参实例化模板... | 模板实例化类中的成员类型type为... |
---|---|
remove_const | 去除类型实参中的常量限定 |
add_const | 在类型实参上添加常量限定 |
remove_pointer | 去除类型实参中的指针属性 |
add_pointer | 在类型实参上添加指针属性 |
remove_reference | 去除类型实参中的引用属性 |
add_lvalue_reference | 在类型实参上添加左值引用 |
add_rvalue_reference | 在类型实参上添加右值引用 |
remove_extent | 去除数组型类型实参的顶层维度 |
remove_all_extents | 去除数组型类型实参的所有维度 |
decay | 衰减类型实参:去除CV限定、去除引用属性、数组变指针、函数变函数指针 |
common_type | 所有类型实参都可被隐式转换到的公共类型 |
······ | ······ |
xxxxxxxxxx
351// convert1.cpp
2
3// 编译期类型转换
4
5
6
7using namespace std;
8
9int main(void) {
10 cout << boolalpha;
11
12 cout << is_same<remove_const<int const>::type, int>::value << endl; // true
13 cout << is_same<add_const<int>::type, int const>::value << endl; // true
14
15 cout << is_same<remove_pointer<int*>::type, int>::value << endl; // true
16 cout << is_same<add_pointer<int>::type, int*>::value << endl; // true
17
18 cout << is_same<remove_reference<int&>::type, int>::value << endl; // true
19 cout << is_same<add_lvalue_reference<int>::type, int&>::value << endl; // true
20 cout << is_same<add_rvalue_reference<int>::type, int&&>::value << endl; // true
21
22 cout << is_same<remove_extent<int[3]>::type, int>::value << endl; // true
23 cout << is_same<remove_extent<int[3][4]>::type, int[4]>::value << endl; // true
24 cout << is_same<remove_all_extents<int[3][4]>::type, int>::value << endl; // true
25
26 cout << is_same<decay<int const volatile>::type, int>::value << endl; // true
27 cout << is_same<decay<int&>::type, int>::value << endl; // true
28 cout << is_same<decay<int[3]>::type, int*>::value << endl; // true
29 cout << is_same<decay<int[3][4]>::type, int (*)[4]>::value << endl; // true
30 cout << is_same<decay<int (int,int)>::type, int (*)(int,int)>::value << endl; // true
31
32 cout << is_same<common_type<bool, char, short>::type, int>::value << endl; // true
33
34 return 0;
35}
根据模板的类型参数创建对象时,需要去除其引用属性。
xxxxxxxxxx
621// convert2.cpp
2
3// 去除模板类型参数中的引用属性
4
5
6
7using namespace std;
8
9class Add {
10public:
11 Add(int x = 0, int y = 0) : x(x), y(y) {}
12
13 int calc(void) const {
14 return x + y;
15 }
16
17private:
18 int x, y;
19};
20
21class Sub {
22public:
23 Sub(int x = 0, int y = 0) : x(x), y(y) {}
24
25 int calc(void) const {
26 return x - y;
27 }
28
29private:
30 int x, y;
31};
32
33// 模板的类型参数可能会是引用类型,而创建对象所需要的是原始
34// 类型而非引用类型,且函数的返回值亦不可能是指向引用的指针
35/*
36template<typename T>
37T* create(int x, int y) {
38 return new T(x, y);
39}
40*/
41template<typename T>
42typename add_pointer<typename remove_reference<T>::type>::type create (int x, int y) {
43 return new typename remove_reference<T>::type(x, y);
44}
45
46template<typename T>
47int calc(T const& c, int x, int y) {
48 return create<decltype(c)>(x, y)->calc();
49}
50
51int main(void) {
52 cout << create<Add>(123, 456)->calc() << endl; // 579
53 cout << create<Sub>(456, 123)->calc() << endl; // 333
54
55 Add add;
56 Sub sub;
57
58 cout << calc(add, 123, 456) << endl; // 579
59 cout << calc(sub, 456, 123) << endl; // 333
60
61 return 0;
62}
从模板中返回类型参数对象的引用时,需要为其添加引用属性。
xxxxxxxxxx
621// convert3.cpp
2
3// 在模板类型参数上添加引用属性
4
5
6
7using namespace std;
8
9class Add {
10public:
11 Add(int x = 0, int y = 0) : x(x), y(y) {}
12
13 int calc(void) const {
14 return x + y;
15 }
16
17private:
18 int x, y;
19};
20
21class Sub {
22public:
23 Sub(int x = 0, int y = 0) : x(x), y(y) {}
24
25 int calc(void) const {
26 return x - y;
27 }
28
29private:
30 int x, y;
31};
32
33// 模板的类型参数可能会是引用类型,而创建对象所需要的是原始
34// 类型而非引用类型,且函数的返回值亦不可能是引用引用的引用
35/*
36template<typename T>
37T& create(int x, int y) {
38 return *new T(x, y);
39}
40*/
41template<typename T>
42typename add_lvalue_reference<typename remove_reference<T>::type>::type create(int x, int y) {
43 return *new typename remove_reference<T>::type (x, y);
44}
45
46template<typename T>
47int calc(T const& c, int x, int y) {
48 return create<decltype(c)>(x, y).calc();
49}
50
51int main(void) {
52 cout << create<Add>(123, 456).calc() << endl; // 579
53 cout << create<Sub>(456, 123).calc() << endl; // 333
54
55 Add add;
56 Sub sub;
57
58 cout << calc(add, 123, 456) << endl; // 579
59 cout << calc(sub, 456, 123) << endl; // 333
60
61 return 0;
62}
xxxxxxxxxx
741// convert4.cpp
2
3// 去除模板类型参数中的常量限定
4
5
6
7using namespace std;
8
9class Integer {
10public:
11 Integer(int n = 0) : n(n) {}
12
13 Integer& operator++(void) {
14 ++n;
15
16 return *this;
17 }
18
19 friend ostream& operator<<(ostream& os, Integer const& i) {
20 return os << i.n;
21 }
22
23private:
24 int n;
25};
26
27// 普通
28
29template<typename T>
30T& create1(int n) {
31 return *new T(n);
32}
33
34// 去除引用属性
35
36template<typename T>
37typename add_lvalue_reference<typename remove_reference<T>::type>::type create2(int n) {
38 return *new typename remove_reference<T>::type(n);
39}
40
41// 去除引用属性和常量限定
42
43template<typename T>
44typename add_lvalue_reference<typename remove_const<typename remove_reference<T>::type>::type>::type create3(int n) {
45 return *new typename remove_const<typename remove_reference<T>::type>::type(n);
46}
47
48// 去除引用属性和CV限定
49
50template<typename T>
51typename add_lvalue_reference<typename remove_cv<typename remove_reference<T>::type>::type>::type create4(int n) {
52 return *new typename remove_cv<typename remove_reference<T>::type>::type(n);
53}
54
55// 去除引用属性和CV限定——衰减
56
57template<typename T>
58typename add_lvalue_reference<typename decay<T>::type>::type create5(int n) {
59 return *new typename decay<T>::type(n);
60}
61
62int main(void) {
63 cout << ++create1<Integer>(100) << endl;
64 cout << ++create2<Integer&>(200) << endl;
65 cout << ++create3<Integer const&>(300) << endl;
66 cout << ++create4<Integer const volatile&>(400) << endl;
67
68 cout << ++create5<Integer>(100) << endl;
69 cout << ++create5<Integer&>(200) << endl;
70 cout << ++create5<Integer const&>(300) << endl;
71 cout << ++create5<Integer const volatile&>(400) << endl;
72
73 return 0;
74}
函数类型不能直接声明变量。要想用它声明变量,以便后续调用,就需要将其升级为函数对象类型,或降级为函数指针类型。
xxxxxxxxxx
361// convert5.cpp
2
3// 将函数类型衰减为函数指针类型
4
5
6
7
8using namespace std;
9
10template<typename Notify>
11class Processor {
12public:
13 Processor(Notify& notify) : fobj(notify), fptr(notify) {}
14
15 void run(void) {
16 fobj(100);
17
18 fptr(200);
19 }
20
21private:
22 // Notify notify; // 函数类型不能直接声明变量
23 function<Notify> fobj; // 要么升级为函数对象类型
24 typename decay<Notify>::type fptr; // 要么降级为函数指针类型
25};
26
27void notify(int eventId) {
28 cout << eventId << endl;
29}
30
31int main(void) {
32 Processor<void (int)> processor(notify);
33 processor.run();
34
35 return 0;
36}
template<bool B, typename T = void> struct enable_if;
传递给模板布尔型形参B的值为... | 模板实例化类中的成员类型type为... |
---|---|
true | 传递给模板类型形参T的类型实参,缺省为void |
false | 无效,引发编译错误 |
xxxxxxxxxx
691// enable1.cpp
2
3// enable_if的基本用法
4
5
6
7
8using namespace std;
9
10// 函数的参数必须是整数类型
11
12template<typename T>
13void foo(typename enable_if<is_integral<T>::value, T>::type arg) {
14 cout << typeid(arg).name() << endl;
15}
16
17// 函数的返回值必须是整数类型
18
19template<typename T>
20typename enable_if<is_integral<T>::value, T>::type bar(void) {
21 return T();
22}
23
24// 模板的参数必须是整数类型
25
26template<typename T, typename = typename enable_if<is_integral<T>::value>::type>
27class A {
28public:
29 static void hum(void) {
30 cout << typeid(T).name() << endl;
31 }
32};
33
34// 针对类型参数取任意类型的通用版本
35
36template<typename T, typename = void>
37class B {
38public:
39 static void fun(void) {
40 cout << "通用版本:" << typeid(T).name() << endl;
41 }
42};
43
44// 针对类型参数取整数类型的特化版本
45
46template<typename T>
47class B<T, typename enable_if<is_integral<T>::value>::type> {
48public:
49 static void fun(void) {
50 cout << "特化版本:" << typeid(T).name() << endl;
51 }
52};
53
54int main(void) {
55 foo<char>(1);
56 // foo<double>(1.); // 编译错误
57
58 cout << typeid(bar<short>()).name() << endl;
59 // cout << typeid(bar<double>()).name() << endl; // 编译错误
60
61 A<int>::hum();
62 // A<double>::hum();
63
64 B<long>::fun(); // ->特化版本
65 B<long long>::fun(); // ->特化版本
66 B<double>::fun(); // ->通用版本
67
68 return 0;
69}
一般而言,(模板)函数间的重载,需要有差异化的参数表,而enable_if则打破了这一限制。
xxxxxxxxxx
1221// enable2.cpp
2
3// 基于enable_if的函数重载
4
5
6
7using namespace std;
8
9// 整数版本
10
11template<typename T>
12typename enable_if<is_integral<T>::value, int>::type foo(T const& arg) {
13 return 1;
14}
15
16// 指针版本
17
18template<typename T>
19typename enable_if<is_pointer<T>::value, int>::type foo(T const& arg) {
20 return 2;
21}
22
23// 数组版本
24
25template<typename T>
26typename enable_if<is_array<T>::value, int>::type foo(T const& arg) {
27 return 3;
28}
29
30// 字符串版本
31
32template<typename T>
33typename enable_if<is_same<T, string>::value, int>::type foo(T const& arg) {
34 return 4;
35}
36
37// enable_if模板第二个参数的缺省值是void,对于没有返回值的函数,该参数可省略不写
38
39template<typename T>
40typename enable_if<is_integral<T>::value>::type bar(T const& arg) {
41 cout << "整数版本" << endl;
42}
43
44template<typename T>
45typename enable_if<is_pointer<T>::value>::type bar(T const& arg) {
46 cout << "指针版本" << endl;
47}
48
49template<typename T>
50typename enable_if<is_array<T>::value>::type bar(T const& arg) {
51 cout << "数组版本" << endl;
52}
53
54template<typename T>
55typename enable_if<is_same<T, string>::value>::type bar(T const& arg) {
56 cout << "字符串版本" << endl;
57}
58
59// 基于enable_if的函数重载,有助于降低与类型判断有关的复杂度
60
61class A {};
62class B {};
63class C {};
64class D {};
65
66template<typename T>
67void hum1(void) {
68 if (typeid(T) == typeid(A))
69 cout << 'A' << endl;
70 else
71 if (typeid(T) == typeid(B))
72 cout << 'B' << endl;
73 else
74 if (typeid(T) == typeid(C))
75 cout << 'C' << endl;
76 else
77 cout << 'X' << endl;
78}
79
80template<typename T>
81typename enable_if<is_same<T, A>::value>::type hum(void) {
82 cout << 'A' << endl;
83}
84
85template<typename T>
86typename enable_if<is_same<T, B>::value>::type hum(void) {
87 cout << 'B' << endl;
88}
89
90template<typename T>
91typename enable_if<is_same<T, C>::value>::type hum(void) {
92 cout << 'C' << endl;
93}
94
95template<typename T>
96typename enable_if<!is_same<T, A>::value && !is_same<T, B>::value && !is_same<T, C>::value>::type hum(void) {
97 cout << 'X' << endl;
98}
99
100int main(void) {
101 char c = 'A';
102 char const* p = "A";
103 char a[] = "A";
104 string s = "A";
105
106 cout << foo(c) << endl;
107 cout << foo(p) << endl;
108 cout << foo(a) << endl;
109 cout << foo(s) << endl;
110
111 bar(c);
112 bar(p);
113 bar(a);
114 bar(s);
115
116 hum<A>();
117 hum<B>();
118 hum<C>();
119 hum<D>();
120
121 return 0;
122}
template<bool B, typename T, typename F> struct conditional;
传递给模板布尔型形参B的值为... | 模板实例化类中的成员类型type为... |
---|---|
true | 传递给模板第一个类型形参T的类型实参 |
false | 传递给模板第二个类型形参F的类型实参 |
xxxxxxxxxx
301// condition1.cpp
2
3// 根据条件选择类型
4
5
6
7
8using namespace std;
9
10int main(void) {
11 using A = conditional<true, short, float>::type; // short
12 using B = conditional<false, short, float>::type; // float
13
14 cout << typeid(A).name() << endl;
15 cout << typeid(B).name() << endl;
16
17 using C = conditional<is_integral<A>::value, long, double>::type; // long
18 using D = conditional<is_integral<B>::value, long, double>::type; // double
19
20 cout << typeid(C).name() << endl;
21 cout << typeid(D).name() << endl;
22
23 using E = conditional<sizeof(A) < sizeof(C), A, C>::type; // short
24 using F = conditional<sizeof(D) < sizeof(B), B, D>::type; // double
25
26 cout << typeid(E).name() << endl;
27 cout << typeid(F).name() << endl;
28
29 return 0;
30}
xxxxxxxxxx
471// result1.cpp
2
3// 借助decltype获取返回值的类型
4
5
6
7
8using namespace std;
9
10// 可调用对象fun的类型Fun是函数模板foo的类型参数,而foo
11// 的返回类型又由fun决定,因此无法直接写出foo的返回类型
12/*
13template<typename Fun, typename Arg>
14? foo(Fun fun, Arg arg) {
15 return fun(arg);
16}
17*/
18// 借助decltype固然可以获取函数的返回类型,但代码晦涩难懂,可读性差
19/*
20template<typename Fun, typename Arg>
21decltype((*(Fun*)0)(*(Arg*)0)) foo(Fun fun, Arg arg) {
22 return fun(arg);
23}
24*/
25// 利用返回类型后置可以简化其书写形式
26
27template<typename Fun, typename Arg>
28auto foo(Fun fun, Arg arg) -> decltype(fun(arg)) {
29 return fun(arg);
30}
31
32int s2i(string const& s) {
33 return atoi(s.c_str());
34}
35
36string i2s(int i) {
37 ostringstream oss;
38 oss << i;
39 return oss.str();
40}
41
42int main(void) {
43 cout << foo(s2i, "123") << endl;
44 cout << foo(i2s, 456) << endl;
45
46 return 0;
47}
xxxxxxxxxx
321// result2.cpp
2
3// 借助declval和decltype获取返回值的类型
4
5
6
7
8using namespace std;
9
10class A {
11public:
12 int operator()(int arg) {
13 return arg;
14 }
15
16private:
17 A(void); // 私有缺省构造函数
18};
19
20int main(void) {
21 // 私有缺省构造函数导致以下代码无法通过编译
22
23 // decltype(A()(0)) n = 0; // 编译错误
24
25 // declval可以获取任何类型的临时变量而无需调用构造函
26 // 数,这样的临时变量可以用于类型推导,但不能用于求值
27
28 decltype(declval<A>()(declval<int>())) n = 0;
29 cout << typeid(n).name() << endl;
30
31 return 0;
32}
假设Fun为某种可调用对象的类型,Arg1,Arg2,...,为传递给该可调用对象的各个参数的类型,则类模板result_of用Fun(Arg1,Arg2,...)实例化所得类中的成员类型type,即为该可调用对象返回值的类型。
xxxxxxxxxx
441// result3.cpp
2
3// 借助result_of获取返回值的类型
4
5
6
7
8
9using namespace std;
10
11template<typename Fun, typename Arg>
12typename result_of<Fun(Arg)>::type foo(Fun fun, Arg arg) {
13 return fun(arg);
14}
15
16int s2i(string const& s) {
17 return atoi(s.c_str());
18}
19
20string i2s(int i) {
21 ostringstream oss;
22 oss << i;
23 return oss.str();
24}
25
26class A {
27public:
28 int operator()(int arg) {
29 return arg;
30 }
31
32private:
33 A(void); // 私有缺省构造函数
34};
35
36int main(void) {
37 cout << foo(s2i, "123") << endl;
38 cout << foo(i2s, 456) << endl;
39
40 result_of<A(int)>::type n = 0;
41 cout << typeid(n).name() << endl;
42
43 return 0;
44}
x
1// result4.cpp
2
3// result_of的基本用法
4
5
6
7
8using namespace std;
9
10// 函数
11
12int fun(int x) {
13 cout << __FUNCTION__ << '(' << x << ")->" << flush;
14
15 return x;
16}
17
18// 函数指针
19
20using fun_ptr = int (*)(int);
21
22// 函数引用
23
24using fun_ref = int (&)(int);
25
26class Dummy {
27public:
28 int fun(int x) const {
29 cout << __FUNCTION__ << '(' << x << ")->" << flush;
30
31 return x;
32 }
33};
34
35// 成员函数指针
36
37using mem_ptr = int (Dummy::*)(int) const;
38
39// 实现了函数操作符的类
40
41class Foo {
42public:
43 int operator()(int x) const {
44 cout << __FUNCTION__ << '(' << x << ")->" << flush;
45
46 return x;
47 }
48
49 double operator()(double x) const {
50 cout << __FUNCTION__ << '(' << x << ")->" << flush;
51
52 return x;
53 }
54};
55
56// 可被转换为函数指针的类
57
58class Bar {
59 using hum_n = int (*)(int);
60 using hum_d = double (*)(double);
61
62public:
63 operator hum_n(void) const {
64 return hum;
65 }
66
67 operator hum_d(void) const {
68 return hum;
69 }
70
71private:
72 static int hum(int x) {
73 cout << __FUNCTION__ << '(' << x << ")->" << flush;
74
75 return x;
76 }
77
78 static double hum(double x) {
79 cout << __FUNCTION__ << '(' << x << ")->" << flush;
80
81 return x;
82 }
83};
84
85int main (void) {
86 cout << fun(100) << endl;
87
88 fun_ptr pfun = &fun;
89 cout << pfun(200) << endl;
90
91 fun_ref rfun = fun;
92 cout << rfun(300) << endl;
93
94 mem_ptr pmem = &Dummy::fun;
95 cout << (Dummy().*pmem)(400) << endl;
96
97 Foo foo;
98 cout << foo(500) << endl;
99 cout << foo(0.5) << endl;
100
101 Bar bar;
102 cout << bar(600) << endl;
103 cout << bar(0.6) << endl;
104
105 // result_of模板的类型参数必须是一个能被实例化为可调用对象的类型
106 // 及传递给该可调用对象的各个参数的类型。可调用对象包括函数指针、
107 // 函数引用、实现了函数操作符的类对象和可被转换为函数指针的类对
108 // 象,但函数类型不能被实例化为对象,因此下面的写法无法通过编译
109
110 // cout << typeid(result_of<decltype(fun)(int)>::type).name() << endl;
111
112 // 只有将其转换为函数指针或引用,才能作为参数传给result_of模板
113
114 cout << typeid(result_of<decltype(fun)*(int)>::type).name() << endl;
115 cout << typeid(result_of<decay<decltype(fun)>::type(int)>::type).name() << endl;
116 cout << typeid(result_of<decltype(fun)&(int)>::type).name() << endl;
117
118 cout << typeid(result_of<fun_ptr(int)>::type).name() << endl;
119 cout << typeid(result_of<fun_ref(int)>::type).name() << endl;
120 cout << typeid(result_of<mem_ptr(Dummy*,int)>::type).name() << endl;
121 cout << typeid(result_of<Foo(int)>::type).name() << endl;
122 cout << typeid(result_of<Foo(double)>::type).name() << endl;
123 cout << typeid(result_of<Bar(int)>::type).name() << endl;
124 cout << typeid(result_of<Bar(double)>::type).name() << endl;
125
126 return 0;
127}
xxxxxxxxxx
741// result5.cpp
2
3// result_of的应用案例
4
5
6
7
8
9using namespace std;
10
11class Student {
12public:
13 Student(string const& name, int age, float score)
14 : name(name), age(age), score(score) {}
15
16 string getName(void) const {
17 return name;
18 }
19
20 int getAge(void) const {
21 return age;
22 }
23
24 float getScore(void) const {
25 return score;
26 }
27
28 friend ostream& operator<<(ostream& os, Student const& s) {
29 return os << '(' << s.name << ',' << s.age << ',' << s.score << ')';
30 }
31
32private:
33 string name;
34 int age;
35 float score;
36};
37
38// 函数orderBy所返回的多重映射以参数向量students中每个Student类型元素的某个成员变
39// 量作为键,而将该元素作为与之相对应的值。究竟选取哪个成员变量则由(成员)函数指
40// 针参数key决定。该指针目标函数的返回类型即为orderBy函数所返回多重映射中键的类型
41
42template<typename Key>
43multimap<typename result_of<Key(Student*)>::type, Student> orderBy (
44 vector<Student> const& students, Key key) {
45 multimap<typename result_of<Key(Student*)>::type, Student> mm;
46
47 for (auto const& student : students)
48 mm.insert(make_pair((student.*key)(), student));
49
50 return mm;
51}
52
53int main (void) {
54 vector<Student> students {
55 {"zhangfei", 25, 90},
56 {"zhaoyun", 22, 80},
57 {"guanyu", 30, 90},
58 {"huangzhong", 25, 80},
59 {"machao", 22, 70}};
60
61 for (auto const& kv : orderBy(students, &Student::getName))
62 cout << kv.second;
63 cout << endl;
64
65 for (auto const& kv : orderBy(students, &Student::getAge))
66 cout << kv.second;
67 cout << endl;
68
69 for (auto const& kv : orderBy(students, &Student::getScore))
70 cout << kv.second;
71 cout << endl;
72
73 return 0;
74}
在C++98/03中,函数模板只能带有固定数量的模板参数,C++11放开了这一限制,允许为函数模板声明0到任意多个模板参数,其形式就是在typename或class关键字后面写上省略号“...”。形如:
xxxxxxxxxx
41template<typename... TYPES>
2返回类型 函数模板名(调用形参表) {
3 函数体
4}
xxxxxxxxxx
241// vaftmpl1.cpp
2
3// 带有可变参数表的函数模板
4
5
6
7using namespace std;
8
9template<typename... TYPES>
10void foo(TYPES... args) {
11 // args是由0到任意多个不同类型的调用参数组成的参数
12 // 包。打印函数模板调用参数(亦即模板参数)的个数
13
14 cout << sizeof...(args) << endl;
15}
16
17int main(void) {
18 foo();
19 foo(123);
20 foo(123, 4.56);
21 foo(123, 4.56, "789");
22
23 return 0;
24}
借助递归调用展开带有可变参数表的函数模板的参数包,需要提供一个参数包展开函数,和一个递归终止函数,后者是用来终止递归的。
xxxxxxxxxx
351// vaftmpl2.cpp
2
3// 借助递归调用展开参数包
4
5
6
7
8using namespace std;
9
10// 递归终止函数
11
12void foo(void) {
13 cout << "展开终止" << endl;
14}
15
16// 参数包展开函数
17
18template<typename HEAD, typename... REST>
19void foo(HEAD head, REST... rest) {
20 cout << head << ':' << typeid(head).name() << endl;
21
22 // 参数包rest在展开过程中递归调用自身,每调用一次,参数包中的参数就减少一个,直到所
23 // 有的参数都被展开为止。当参数包为空时,调用非模板形式的递归终止函数,结束递归过程
24
25 foo(rest...);
26}
27
28int main(void) {
29 foo();
30 foo(123);
31 foo(123, 4.56);
32 foo(123, 4.56, "789");
33
34 return 0;
35}
借助泛型元组和类型萃取也可以达到同样的效果。
xxxxxxxxxx
471// vaftmpl3.cpp
2
3// 借助递归调用展开参数包
4
5
6
7
8
9using namespace std;
10
11// 递归终止函数
12
13template<size_t I = 0, typename TUPLE>
14typename enable_if<I == tuple_size<TUPLE>::value>::type bar(TUPLE tuple) {
15 // 当参数索引等于参数个数时,递归终止
16
17 cout << "展开终止" << endl;
18}
19
20// 参数包展开函数
21
22template<size_t I = 0, typename TUPLE>
23typename enable_if<I < tuple_size<TUPLE>::value>::type bar(TUPLE tuple) {
24 // 当参数索引小于参数个数时,取当前索引位置的参数
25
26 cout << get<I>(tuple) << ':' << typeid(get<I>(tuple)).name() << endl;
27
28 // 然后通过递增参数索引来选择不同的函数版本
29
30 bar<I+1>(tuple);
31}
32
33template<typename... TYPES>
34void foo(TYPES... args) {
35 // 先将由不同类型不定个数的调用参数组成的参数包转换为泛型元组
36
37 bar(make_tuple(args...));
38}
39
40int main(void) {
41 foo();
42 foo(123);
43 foo(123, 4.56);
44 foo(123, 4.56, "789");
45
46 return 0;
47}
所谓逗号表达式,就是形如“表达式1, 表达式2, 表达式3 ... 表达式n”的表达式。逗号表达式的求值过程是,从左到右依次计算每个表达式的值,以最后一个表达式的值作为整个逗号表达式的值。
xxxxxxxxxx
381// vaftmpl4.cpp
2
3// 借助逗号表达式和列表初始化展开参数包
4
5
6
7
8using namespace std;
9
10template<typename T>
11void bar(T arg) {
12 cout << arg << ':' << typeid(arg).name() << endl;
13}
14
15template<typename... TYPES>
16void foo(TYPES... args) {
17 int arr[]{(bar(args), 0)...};
18
19 // 以上列表初始化将被编译器展开成如下形式:
20 //
21 // int arr[]{(bar(args里的第1个参数), 0), (bar(args里的第2个参数), 0), ...};
22 //
23 // 其中的每一个初值都是一个被圆括号括起来的逗号表达式。为了计
24 // 算该逗号表达式的值,会首先用参数包args里的第n个参数调用bar
25 // 函数,并取逗号后面的0作为该逗号表达式的值。最后,在arr被初
26 // 始化为一个全零数组的同时,参数包中的每一个参数都得到了处理
27
28 cout << "展开终止" << endl;
29}
30
31int main(void) {
32 foo();
33 foo(123);
34 foo(123, 4.56);
35 foo(123, 4.56, "789");
36
37 return 0;
38}
也可以用初始化列表代替数组。
xxxxxxxxxx
291// vaftmpl5.cpp
2
3// 借助逗号表达式和列表初始化展开参数包
4
5
6
7
8using namespace std;
9
10template<typename T>
11void bar(T arg) {
12 cout << arg << ':' << typeid(arg).name() << endl;
13}
14
15template<typename... TYPES>
16void foo(TYPES... args) {
17 initializer_list<int>{(bar(args), 0)...};
18
19 cout << "展开终止" << endl;
20}
21
22int main(void) {
23 foo();
24 foo(123);
25 foo(123, 4.56);
26 foo(123, 4.56, "789");
27
28 return 0;
29}
甚至可以用lambda表达式代替有名函数bar。
xxxxxxxxxx
271// vaftmpl6.cpp
2
3// 借助逗号表达式和列表初始化展开参数包
4
5
6
7
8using namespace std;
9
10template<typename... TYPES>
11void foo(TYPES... args) {
12 initializer_list<int>{([&] {
13 cout << args << ':' << typeid(args).name() << endl; }(), 0)...};
14
15 cout << "展开终止" << endl;
16}
17
18int main(void) {
19 foo();
20 foo(123);
21 foo(123, 4.56);
22 foo(123, 4.56, "789");
23
24 return 0;
25}
26
27// 本程序代码无法使用GNU C++编译器编译通过,建议使用Visual Studio 2013以上版本编译器
在C++98/03中,类模板只能带有固定数量的模板参数,C++11放开了这一限制,允许为类模板声明0到任意多个模板参数,其形式就是在typename或class关键字后面写上省略号“...”。形如:
xxxxxxxxxx
61template<typename... TYPES>
2class 类模板名 [: 继承表] {
3 成员类型
4 成员函数
5 成员变量
6};
xxxxxxxxxx
271// vactmpl1.cpp
2
3// 带有可变参数表的类模板
4
5
6
7using namespace std;
8
9template<typename... TYPES>
10class Foo {
11public:
12 Foo(TYPES... args) {
13 // args是由0到任意多个不同类型的调用参数组成的参数
14 // 包。打印构造函数调用参数(亦即模板参数)的个数
15
16 cout << sizeof...(args) << endl;
17 }
18};
19
20int main(void) {
21 Foo<> a;
22 Foo<int> b(123);
23 Foo<int, double> c(123, 4.56);
24 Foo<int, double, char const*> d(123, 4.56, "789");
25
26 return 0;
27}
借助模板特化展开带有可变参数表的类模板的参数包,需要提供一个接受任意多个模板参数的通用版本、一个接受至少一个模板参数的特化版本,和一个不接受任何模板参数的特化版本。
xxxxxxxxxx
491// vactmpl2.cpp
2
3// 借助模板特化展开参数包
4
5
6
7
8using namespace std;
9
10// 接受任意多个模板参数的通用版本
11
12template<typename... TYPES> class Foo; // 只需声明,无需定义
13
14// 接受至少一个模板参数的特化版本
15
16template<typename HEAD, typename... REST>
17class Foo<HEAD, REST...> {
18public:
19 Foo(HEAD head, REST... rest) : head(head), rest(rest...) {
20 cout << head << ':' << typeid(head).name() << endl;
21 }
22
23private:
24 HEAD head;
25
26 // 参数包REST在展开过程中实例化类模板自身,每实例化一次,
27 // 参数包中的参数就减少一个,直到所有的参数都被展开为止。
28 // 当参数包为空时,将会选择不接受任何类型参数的特化版本
29
30 Foo<REST...> rest;
31};
32
33// 不接受任何模板参数的特化版本
34
35template<> class Foo<> {
36public:
37 Foo(void) {
38 cout << "展开终止" << endl;
39 }
40};
41
42int main(void) {
43 Foo<> a;
44 Foo<int> b(123);
45 Foo<int, double> c(123, 4.56);
46 Foo<int, double, char const*> d(123, 4.56, "789");
47
48 return 0;
49}
使用继承语法也可以达到同样的效果。
xxxxxxxxxx
471// vactmpl3.cpp
2
3// 借助模板特化展开参数包
4
5
6
7
8using namespace std;
9
10// 接受任意多个模板参数的通用版本
11
12template<typename... TYPES> class Foo; // 只需声明,无需定义
13
14// 接受至少一个模板参数的特化版本
15
16template<typename HEAD, typename... REST>
17class Foo<HEAD, REST...> : public Foo<REST...> {
18 // 参数包REST在展开过程中实例化类模板自身,每实例化一次,
19 // 参数包中的参数就减少一个,直到所有的参数都被展开为止。
20 // 当参数包为空时,将会选择不接受任何类型参数的特化版本
21
22public:
23 Foo(HEAD head, REST... rest) : head(head), Foo<REST...>(rest...) {
24 cout << head << ':' << typeid(head).name() << endl;
25 }
26
27private:
28 HEAD head;
29};
30
31// 不接受任何模板参数的特化版本
32
33template<> class Foo<> {
34public:
35 Foo(void) {
36 cout << "展开终止" << endl;
37 }
38};
39
40int main(void) {
41 Foo<> a;
42 Foo<int> b(123);
43 Foo<int, double> c(123, 4.56);
44 Foo<int, double, char const*> d(123, 4.56, "789");
45
46 return 0;
47}
xxxxxxxxxx
621// vactmpl4.cpp
2
3// 借助泛型元组和索引生成器展开参数包
4
5
6
7
8
9using namespace std;
10
11// 索引序列
12
13template<int...> class IndexSequence {};
14
15// 索引生成器通用版本
16
17template<int N, int... INDEXES>
18class IndexMaker {
19public:
20 using Indexes = typename IndexMaker<N - 1, N - 1, INDEXES...>::Indexes;
21};
22
23// 索引生成器N取0的特化版本
24
25template<int... INDEXES>
26class IndexMaker<0, INDEXES...> {
27public:
28 using Indexes = IndexSequence<INDEXES...>;
29};
30
31template<typename... TYPES>
32class Foo {
33public:
34 Foo(TYPES... args) {
35 printArgs(typename IndexMaker<sizeof...(args)>::Indexes(), make_tuple(args...));
36 }
37
38 // 打印参数元组
39
40 template<int... INDEXES>
41 void printArgs(IndexSequence<INDEXES...>, tuple<TYPES...>&& args) {
42 initializer_list<int>{(printArg(get<INDEXES>(args)), 0)...};
43
44 cout << "展开终止" << endl;
45 }
46
47 // 打印单个参数
48
49 template<typename T>
50 void printArg(T arg) {
51 cout << arg << ':' << typeid(arg).name() << endl;
52 }
53};
54
55int main(void) {
56 Foo<> a;
57 Foo<int> b(123);
58 Foo<int, double> c(123, 4.56);
59 Foo<int, double, char const*> d(123, 4.56, "789");
60
61 return 0;
62}
xxxxxxxxxx
331// print1.cpp
2
3// C++98/03中的通用打印函数
4
5
6
7using namespace std;
8
9// 几乎完全相同的模板定义代码大量重复
10
11template<typename TYPE>
12void print(TYPE arg) {
13 cout << arg << endl;
14}
15
16template<typename TYPE1, typename TYPE2>
17void print(TYPE1 arg1, TYPE2 arg2) {
18 cout << arg1 << ' ' << arg2 << endl;
19}
20
21template<typename TYPE1, typename TYPE2, typename TYPE3>
22void print(TYPE1 arg1, TYPE2 arg2, TYPE3 arg3) {
23 cout << arg1 << ' ' << arg2 << ' ' << arg3 << endl;
24}
25
26int main(void) {
27 print(123);
28 print(123, 4.56);
29 print(123, 4.56, "789");
30 // print(123, 4.56, "789", '0'); // 最多只能支持三个任意类型数据的打印
31
32 return 0;
33}
xxxxxxxxxx
291// print2.cpp
2
3// C++11中的通用打印函数
4
5
6
7using namespace std;
8
9// 代码简洁优雅,完全消除重复
10
11void print(void) {
12 cout << endl;
13}
14
15template<typename HEAD, typename... REST>
16void print(HEAD head, REST... rest) {
17 cout << head << ' ';
18
19 print(rest...);
20}
21
22int main(void) {
23 print(123);
24 print(123, 4.56);
25 print(123, 4.56, "789");
26 print(123, 4.56, "789", '0'); // 支持任意多个任意类型数据的打印
27
28 return 0;
29}
xxxxxxxxxx
971// factory1.cpp
2
3// C++98/03中的通用工厂
4
5
6
7using namespace std;
8
9// 几乎完全相同的模板定义代码大量重复
10
11template<typename CLASS, typename TYPE>
12CLASS* create(TYPE arg) {
13 return new CLASS(arg);
14}
15
16template<typename CLASS, typename TYPE1, typename TYPE2>
17CLASS* create(TYPE1 arg1, TYPE2 arg2) {
18 return new CLASS(arg1, arg2);
19}
20
21template<typename CLASS, typename TYPE1, typename TYPE2, typename TYPE3>
22CLASS* create(TYPE1 arg1, TYPE2 arg2, TYPE3 arg3) {
23 return new CLASS(arg1, arg2, arg3);
24}
25
26class One {
27public:
28 One(int arg) : var(arg) {}
29
30 friend ostream& operator<<(ostream& os, One const& one) {
31 return os << one.var;
32 }
33
34private:
35 int var;
36};
37
38class Two {
39public:
40 Two(int arg1, double arg2) : var1(arg1), var2(arg2) {}
41
42 friend ostream& operator<<(ostream& os, Two const& two) {
43 return os << two.var1 << ' ' << two.var2;
44 }
45
46private:
47 int var1;
48 double var2;
49};
50
51class Three {
52public:
53 Three(int arg1, double arg2, char const* arg3)
54 : var1(arg1), var2(arg2), var3(arg3) {}
55
56 friend ostream& operator<<(ostream& os, Three const& three) {
57 return os << three.var1 << ' ' << three.var2 << ' ' << three.var3;
58 }
59
60private:
61 int var1;
62 double var2;
63 char const* var3;
64};
65
66class Four {
67public:
68 Four(int arg1, double arg2, char const* arg3, char arg4)
69 : var1(arg1), var2(arg2), var3(arg3), var4(arg4) {}
70
71 friend ostream& operator<<(ostream& os, Four const& four) {
72 return os << four.var1 << ' ' << four.var2 << ' ' <<
73 four.var3 << ' ' << four.var4;
74 }
75
76private:
77 int var1;
78 double var2;
79 char const* var3;
80 char var4;
81};
82
83int main(void) {
84 One* one = create<One>(123);
85 cout << *one << endl;
86
87 Two* two = create<Two>(123, 4.56);
88 cout << *two << endl;
89
90 Three* three = create<Three>(123, 4.56, "789");
91 cout << *three << endl;
92
93 // Four* four = create<Four>(123, 4.56, "789", '0'); // 最多支持三个构造实参
94 // cout << *four << endl;
95
96 return 0;
97}
xxxxxxxxxx
941// factory2.cpp
2
3// C++11中的通用工厂
4
5
6
7using namespace std;
8
9// 代码简洁优雅,完全消除重复
10/*
11template<typename CLASS, typename... TYPES>
12CLASS* create(TYPES... args) {
13 return new CLASS(args...);
14}
15*/
16// 更优化的版本
17
18template<typename CLASS, typename... TYPES>
19CLASS* create(TYPES&&... args) { // 引用传参,避免复制,提高性能
20 return new CLASS(forward<TYPES>(args)...); // 通过完美转发保持参数左右值引用不变
21}
22
23class One {
24public:
25 One(int arg) : var(arg) {}
26
27 friend ostream& operator<<(ostream& os, One const& one) {
28 return os << one.var;
29 }
30
31private:
32 int var;
33};
34
35class Two {
36public:
37 Two(int arg1, double arg2) : var1(arg1), var2(arg2) {}
38
39 friend ostream& operator<<(ostream& os, Two const& two) {
40 return os << two.var1 << ' ' << two.var2;
41 }
42
43private:
44 int var1;
45 double var2;
46};
47
48class Three {
49public:
50 Three(int arg1, double arg2, char const* arg3)
51 : var1(arg1), var2(arg2), var3(arg3) {}
52
53 friend ostream& operator<<(ostream& os, Three const& three) {
54 return os << three.var1 << ' ' << three.var2 << ' ' << three.var3;
55 }
56
57private:
58 int var1;
59 double var2;
60 char const* var3;
61};
62
63class Four {
64public:
65 Four(int arg1, double arg2, char const* arg3, char arg4)
66 : var1(arg1), var2(arg2), var3(arg3), var4(arg4) {}
67
68 friend ostream& operator<<(ostream& os, Four const& four) {
69 return os << four.var1 << ' ' << four.var2 << ' ' <<
70 four.var3 << ' ' << four.var4;
71 }
72
73private:
74 int var1;
75 double var2;
76 char const* var3;
77 char var4;
78};
79
80int main (void) {
81 One* one = create<One>(123);
82 cout << *one << endl;
83
84 Two* two = create<Two>(123, 4.56);
85 cout << *two << endl;
86
87 Three* three = create<Three>(123, 4.56, "789");
88 cout << *three << endl;
89
90 Four* four = create<Four>(123, 4.56, "789", '0'); // 支持任意多个构造实参
91 cout << *four << endl;
92
93 return 0;
94}