赞
踩
个人主页:Lei宝啊
愿所有美好如期而遇
这种初始化方式我们建议用第一种,但是以后看见下面两种也不要感到疑惑,是可以这样初始化的。
- int main()
- {
-
- int a = 1;
- int b = { 1 };
- int c{ 1 };
-
- return 0;
- }
我们简单实现一个日期类
- class Date
- {
- public:
- Date(){}
-
- Date(int year, int month, int day)
- :_year(year)
- ,_month(month)
- ,_day(day)
- {}
-
- private:
- size_t _year;
- size_t _month;
- size_t _day;
-
- };
-
- int main()
- {
-
- Date a;
- Date b(1, 1, 1);
- Date c{ 1,1,1 };
-
- //多参数的隐式类型转换,{1,1,1}构造一个Date类型的临时对象,去拷贝构造d对象。
- Date d = { 1,1,1 };
-
- return 0;
- }
- #include <vector>
- using namespace std;
-
- int main()
- {
-
- //与Date是不同的,这里不是多参数隐式类型转换,
- //是C++11特性,添加了initializer_list构造函数
-
- vector<int> v = { 1,2,3,4,5,6 };
-
- /*
- 底层是这样的
- vector(initializer_list<value_type> il)
- {
- for(auto &e : il)
- {
- *finish = e;
- finish++;
- }
- }
- */
-
- vector<int> v{ 1,2,3,4,5,6 };
-
- return 0;
- }
initializer_list是个模板类,只要我们使用{},像下面那样,那么类型就是initializer_list。
auto il = { 10, 20, 30 }; // the type of il is an initializer_list
所有容器在C++11都新增了这样的构造函数。
所以我们可以这样使用:
vector<int> v = { 1,2,3,4,5,6 };
原理就是{1,2,3,4,5,6}先构造一个initializer_list对象,再使用这个对象进行拷贝构造,或者我们可以直接这样:
- //直接构造
- vector<int> v({ 1,2,3,4,5,6 });
-
-
- //其实就类似于这样:
-
- //单参数隐式类型转换,先构造再拷贝构造
- //string s = "hello world !";
-
- //直接构造
- //string s("hello world !");
那么我们走一遍这个代码的流程:vector<int> v = { 1,2,3,4,5,6 };
首先v需要进行拷贝构造,而构造他的对象的类型应该是initializer_list<int>,所以使用{1,2,3,4,5,6}构造一个Initializer_list<int>的对象,然后对v进行拷贝构造。
在这个拷贝构造中,将initializer_list对象中的元素全部取出挨个赋给vector。
map<string, int> m3 = {{"1",1},{"2",2}};
map元素的类型为pair<string,int>,并且需要进行拷贝构造,这样的一个对象类型为initializer_list<pair<string,int>>,于是需要使用{"1",1},{"2",2}构造一个pair<string,int>类型的对象,我们看pair:
所以构造pair时first_type的类型应该是const char*,而不是string,所以这里还需要多一层构造。
C++11于是新增了这样的构造函数:
我们写代码来理解这个构造函数:
- template<T1, T2>
- struct pair
- {
-
- //C++98
- pair(const T& key, const T& value)
- :fisrt(key)
- ,second(value)
- {}
-
- //C++11
- template<U, V>
- pair(U&& a, V&& b)
- :first(a)
- ,second(b)
- {}
-
- T1 first;
- T2 second;
- }
之前,C++98是这样的,pair(const string& key, const int& value)
现在,C++11是这样的,pair(const char*&& a, int&& b),于是这里进行了直接构造,省却了一层拷贝构造,节省了资源。
- #ifndef NULL
- #ifdef __cplusplus
- #define NULL 0
- #else
- #define nullptr ((void *)0)
- #endif
- #endif
这样nullptr就表示空指针。
左值引用、右值引用及移动语义-CSDN博客,这个是博主单独写的(所以也可以看出右值引用的移动语义在C++11中的地位,很重要),这里不再重复去写了。
- #include <iostream>
- #include <string>
- using namespace std;
-
- void Fun(int& x)
- {
- cout << "左值引用" << endl;
- }
-
- void Fun(const int& x)
- {
- cout << "const 左值引用" << endl;
- }
-
- void Fun(int&& x)
- {
- cout << "右值引用" << endl;
- }
-
- void Fun(const int&& x)
- {
- cout << "const 右值引用" << endl;
- }
-
- //万能引用
- /*
- 模板中T&& 不代表右值引用,而是万能引用
- 如果传值为左值,那么就是左值引用
- 如果传值为右值,那么就是右值引用
- */
- template<typename T>
- void PerfectForward(T&& t)
- {
- Fun(t);
- }
-
- int main()
- {
- PerfectForward(10); // 右值
-
- int a;
- PerfectForward(a); // 左值
- PerfectForward(std::move(a)); // 右值
-
- const int b = 8;
- PerfectForward(b); // const 左值
- PerfectForward(std::move(b)); // const 右值
-
- return 0;
- }
但是为什么全成了左值引用呢?我们看PerfectForward函数,我们传右值过去时,也就是右值引用,而右值引用 引用右值后,右值引用属性变为左值,所以调用的全是左值的函数。
于是我们提到完美转发。
- template<typename T>
- void PerfectForward(T&& t)
- {
- //forward<T>(val) 完美转发
- Fun(forward<T>(t));
- }
于是我们使用default:
可变参数模板是模板编程时,模板参数(template parameter)的个数可变的情形。这种模板类型支持一个函数或模板类可以接受任意多个参数,且这些参数可以是任何类型。
可变参数模板是C++ 11新增的最强大的特性之一,它对参数进行高度泛化,能表示0到任意个数、任意类型的参数。
- // Args是一个模板参数包,args是一个函数形参参数包
- // 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。
- template <class ...Args>
- void ShowList(Args... args)
- {}
- #include <iostream>
- #include <string>
- using namespace std;
-
- //终止函数
- template<class T>
- void _ShowList(T value)
- {
- //...
- cout << value << endl;
- }
-
- template<class T, class ...Args>
- void _ShowList(T value, Args... args)
- {
- //...
- cout << value << " ";
- _ShowList(args...);
- }
-
- template <class ...Args>
- void ShowList(Args... args)
- {
- _ShowList(args...);
- }
-
- int main()
- {
- ShowList("string", 1, '?');
- return 0;
- }
在C++98中,如果我们使用sort进行排序,那么我们可以通过控制传给sort的比较对象来进行不同的排序方式:
即不同的comp对象,他可以是静态成员函数名,也可以是重载了operator()的类的对象。
如果我们要对这样的一组数据按照不同方式进行比较:
- struct Goods
- {
- string _name; // 名字
- double _price; // 价格
- int _evaluate; // 评价
- Goods(const char* str, double price, int evaluate)
- :_name(str)
- , _price(price)
- , _evaluate(evaluate)
- {}
- };
那么我们要去写多个不同的仿函数吗?这是不是很麻烦?
所以我们使用lambda表达式就会比较简单,现在我们先介绍lambda表达式:
lambda 表达式书写格式:[capture-list] (parameters) mutable -> return-type { statement }捕捉列表 参数列表 修饰符 返回值 函数体
参数解释说明:
[capture-list] 捕捉列表:该列表总是出现在lambda函数的开始位置,编译器根据[]来判断接下来的代码是否为lambda函数,捕捉列表能够捕捉上下文中的变量供lambda 函数使用。
(parameters) 参数列表:类似于普通函数的参数列表,相同用法。(若不需要参数传递,可以省略)
mutable:当我们使用捕捉列表以值传递方式进行捕捉,使用mutable取消他的常量性,使其在函数体中可以进行修改。(其实用处不大)
return-type:返回值类型,没有返回值时默认为void,此时可省略返回值类型,当返回值类型明确时,返回值类型也可以省略。
statement:函数体,不可省略,在函数体内,不仅可以使用参数,还可以使用捕获到的变量。
举例使用:
- #include <iostream>
- using namespace std;
-
- int main()
- {
-
- int a = 0, b = 1;
-
- // [](int a, int b){return a + b; };
- auto add = [](int a, int b) ->int {return a + b; };
- cout << add(1, 2) << endl;
-
- return 0;
- }
- int main()
- {
-
- int a = 0, b = 1;
-
- auto add = [a, b]() {return a + b; };
- cout << add() << endl;
-
- return 0;
- }
- int main()
- {
-
- int a = 1, b = 2;
-
- auto add = [](int& a, int& b) {
- int temp = a;
- a = b;
- b = temp;
- };
-
- add(a, b);
- cout << "a: " << a << endl;
- cout << "b: " << b << endl;
-
- return 0;
- }
- int main()
- {
-
- int a = 0, int b = 1;
-
- auto add = [a, b]() {
- int temp = a;
- a = b;
- b = temp;
- };
-
- return 0;
- }
- int main()
- {
- int a = 0, b = 1;
-
- auto add = [a, b]()mutable {
- int temp = a;
- a = b;
- b = temp;
- };
-
- add();
- cout << "a: " << a << endl;
- cout << "b: " << b << endl;
-
- return 0;
- }
- int main()
- {
- int a = 0, b = 1;
-
- auto add = [&a, &b](){
- int temp = a;
- a = b;
- b = temp;
- };
-
- add();
- cout << "a: " << a << endl;
- cout << "b: " << b << endl;
-
- return 0;
- }
- int main()
- {
- int a = 0, b = 1;
-
- auto add = [&](){
- int temp = a;
- a = b;
- b = temp;
- };
-
- add();
- cout << "a: " << a << endl;
- cout << "b: " << b << endl;
-
- return 0;
- }
- int main()
- {
- int a = 0, b = 1;
-
- auto add = [=]()mutable{
- int temp = a;
- a = b;
- b = temp;
- };
-
- add();
- cout << "a: " << a << endl;
- cout << "b: " << b << endl;
-
- return 0;
- }
混合使用
- int main()
- {
-
- int a = 0, b = 1, c = 2;
-
- //所有变量以值传递方式捕捉,除了c,c以引用传递方式捕捉
- auto add1 = [=, &c]() {return a + b + c; };
- //所有变量以引用传递方式捕捉,除了c,c以值传递方式捕捉
- auto add2 = [&, c]() {return a + b + c; };
-
- return 0;
- }
- int main()
- {
-
- int a = 1, b = 2;
- auto print = [] {cout << "hello world !\n"; };
-
- print();
-
- return 0;
- }
lambda表达式的底层其实就是仿函数。
- #include <vector>
- #include <algorithm>
-
- struct Goods
- {
- string _name; // 名字
- double _price; // 价格
- int _evaluate; // 评价
- Goods(const char* str, double price, int evaluate)
- :_name(str)
- ,_price(price)
- ,_evaluate(evaluate)
- {}
- };
-
- struct compare
- {
- bool operator()(const Goods& a, const Goods& b)
- {
- return a._price > b._price;
- }
- };
-
- int main()
- {
- vector<Goods> v = { { "苹果", 2.1, 5 }, { "香蕉", 3, 4 }, { "橙子", 2.2,
- 3 }, { "菠萝", 1.5, 4 } };
-
- //sort的compare对象要进行排序的是v的元素,也就是Goods的对象
- sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
- return g1._price > g2._price;
- });
-
- sort(v.begin(), v.end(), [](const Goods& g1, const Goods& g2) {
- return g1._evaluate > g2._evaluate;
- });
-
- sort(v.begin(), v.end(), compare());
-
- return 0;
- }
- double func(double a)
- {
- return a / 2;
- }
-
- struct Functor
- {
- double operator()(double d)
- {
- return d / 3;
- }
- };
-
- template<class F, class T>
- T useF(F f, T x)
- {
- static int count = 0;
- cout << "count:" << ++count << endl;
- cout << "count:" << &count << endl;
-
- //f是什么?仿函数?函数名?lambda表达式?
- return f(x);
- }
-
- int main()
- {
- /*
- 下面这些代码会实例化出三份useF函数
- */
-
- // 函数名
- cout << useF(func, 11.11) << endl;
- // 函数对象
- cout << useF(Functor(), 11.11) << endl;
- // lamber表达式
- cout << useF([](double d){ return d / 4; }, 11.11) << endl;
-
- return 0;
- }
- #include <functional>
-
- double func(double a)
- {
- return a / 2;
- }
-
- struct Functor
- {
- double operator()(double d)
- {
- return d / 3;
- }
- };
-
- template<class F, class T>
- T useF(F f, T x)
- {
- static int count = 0;
- cout << "count:" << ++count << endl;
- cout << "count:" << &count << endl;
-
- //f是什么?仿函数?函数名?lambda表达式?
- return f(x);
- }
-
- int main()
- {
-
- // 函数名
- std::function<double(double)> func1 = func;
- cout << useF(func1, 11.11) << endl;
-
- // 函数对象
- std::function<double(double)> func2 = Functor();
- cout << useF(func2, 11.11) << endl;
-
- // lamber表达式
- std::function<double(double)> func3 = [](double d)->double {return d /4;};
- cout << useF(func3, 11.11) << endl;
-
- return 0;
- }
我们发现function函数只实例化出一份,并且我们上面的这些只是针对于普通函数而言,成员函数我们还没有说过。
- #include <functional>
-
- int Plus(int a, int b)
- {
- return a + b;
- }
-
- class Sub
- {
- public:
- int sub(int a, int b)
- {
- return a - b;
- }
- };
-
- int main()
- {
-
- function<int(Sub, int, int)> f = &Sub::sub;
- cout << f(Sub(), 1, 2) << endl;
-
- return 0;
- }
注意:静态成员函数包装同普通函数。
- #include <iostream>
- #include <functional>
-
- using namespace std;
-
- int Plus(int a, int b)
- {
- return a - b;
- }
-
- class Sub
- {
- public:
- int sub(int a, int b)
- {
- return a - b;
- }
- };
-
-
- int main()
- {
- /*
- 一般函数
- */
-
- function<int(int, int)> f1 = Plus;
-
- //调换参数顺序
- auto func = bind(Plus, placeholders::_2, placeholders::_1);
- cout << func(3, 4) << endl;
-
- //调整参数个数
- auto func1 = bind(Plus, 20, placeholders::_1);
- cout << func1(10) << endl;
-
- /*
- 成员函数:
- 1:静态(同一般)
- 2:非静态
- */
-
- function<int(Sub, int, int)> f2 = &Sub::sub;
- f2(Sub(), 2, 3);
-
- //改变参数数量
- auto func2 = bind(&Sub::sub, Sub(), placeholders::_1, placeholders::_2);
- function<int(int, int)> f3 = func2;
- cout << f3(3, 4) << endl;
- cout << func2(3, 4) << endl;
-
-
- return 0;
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。