怎么做辅助发卡网站,老男孩搭建wordpress,网站兼容怎么调,wordpress顶部空白文章目录 C111. 统一的列表初始化1.1 {}初始化 2. 声明2.1 auto2.2 decltype2.3 nullptr 3. 右值引用和移动语义3.1 左值引用和右值引用3.2 左值引用与右值引用比较3.3 右值引用使用的场景和意义3.4 完美转发 4. 可变参数模板5. lambda表达式5.1 函数对象与lambda表达式 6. 线程… 文章目录 C111. 统一的列表初始化1.1 {}初始化 2. 声明2.1 auto2.2 decltype2.3 nullptr 3. 右值引用和移动语义3.1 左值引用和右值引用3.2 左值引用与右值引用比较3.3 右值引用使用的场景和意义3.4 完美转发 4. 可变参数模板5. lambda表达式5.1 函数对象与lambda表达式 6. 线程库6.1 thread类的简单介绍6.2 线程函数参数 7. 包装器8.bind C11
1. 统一的列表初始化
1.1 {}初始化
C11扩大了用大括号括起来的列表的使用范围。使其适用于所有的内置类型和用户自定义的类型。使用初始化列表时可以添加等号也可以不添加
2. 声明
2.1 auto
C11当中将其用于实现自动类型推断这样要求必须进行显示初始化让编译器将定义对象的类型设置为初始化值的类型。
2.2 decltype
将变量的类型声明为表达式指定的类型
2.3 nullptr
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif3. 右值引用和移动语义
3.1 左值引用和右值引用
传统的C语法当中就有引用的概念C11当中增加了右值引用语法特性。无论是左值引用还是右值引用都是给变量起别名
什么是左值什么是右值 左值表示一个数据的表达式如变量名或者解引用的指针我们可以获取它的地址可以对它赋值。左值可以出现在赋值符号的左边右值不能出现在赋值符号的左边 int main() {// 以下都是左值int* p new int(0);int b 1;const int c 2;// 一下都是左值的引用int* rp p;int rb b;const int rc c;int value *p;return 0;
}什么是右值什么是右值引用
右值也是一个数据的表达式。如 字面常量、表达式返回值、函数返回值这个不能是左值引用返回。右值不能出现在赋值符号的左边右值不能取地址。右值引用就是对右值的引用给右值起别名。 int main()
{double x 1.1, y 2.2;
// 以下几个都是常见的右值10;x y;fmin(x, y);
// 以下几个都是对右值的右值引用int rr1 10;double rr2 x y;double rr3 fmin(x, y);
// 这里编译会报错error C2106: “”: 左操作数必须为左值10 1;x y 1;fmin(x, y) 1;return 0;
}需要注意的是右值是不能取地址的但是给右值取别名之后会导致右值存储到特别的位置并且可以取到该位置的地址。
int main() {double x 1.1, y 2.2;int rr1 10;const double rr2 x y;rr1 20;rr2 5.5; // 报错return 0;
}3.2 左值引用与右值引用比较
左值引用总结
左值引用只能引用左值不能引用右值const左值引用既可以引用左值也可以引用右值
右值引用总结
右值引用只能引用右值不能引用左值右值引用可以引用move以后的左值
3.3 右值引用使用的场景和意义
左值引用的短板 只能使用传值返回传值返回会导致至少一次拷贝构造
移动构造本质是将参数右值的资源窃取过来占为已有。那么就不用做深拷贝了所以叫做移动构造。就是窃取别人的资源来构造自己
不仅仅有移动构造还有移动赋值 3.4 完美转发
模板当中的 不代表右值引用。而是万能引用。既能接收左值又能接收右值。模板的万能引用只是提供了同时接收左值引用又能接收右值引用。但是引用类型的唯一作用就是限制了接收的类型后续引用中都退化成为了左值。如果在传递的过程当中保持左值或右值的属性就需要这个完美转发了
forward保证了传参过程中的原生类型属性
强制生成默认函数的关键字default
比如我们提供了拷贝构造就不会生成移动构造了我们可以使用default关键字显示指定移动构造生成
禁止生成默认构造函数的关键字delete
4. 可变参数模板
templateclass...Args
void show(Args...args) {}递归方式展开参数包
// 递归终止函数
template class T
void ShowList(const T t)
{cout t endl;
}
// 展开函数
template class T, class ...Args
void ShowList(T value, Args... args)
{cout value ;ShowList(args...);
}
int main()
{ShowList(1);ShowList(1, A);ShowList(1, A, std::string(sort));return 0;
}5. lambda表达式
lambda表达式实际上是一个匿名函数
lambda表达式的书写格式
[capture-list] (parameters) mutable-return-type{statement}
int main() {int a 3, b 4;[]{return a b;};auto fun1 [](int c){b a c;};fun1(10);cout b a endl;// 复制捕捉xint x 20;auto add_x [x](int a) mutable {x * 2;return a x;};cout add_x(10) endl;cout typeid(a).name() endl;cout typeid(add_x(10)).name() endl;
}[var]表示值传递方式捕捉变量var[]表示值传递方式捕捉所有父作用域中的变量[var]表示引用传递捕捉变量var[] 表示引用传递所有父作用域中的变量[this]表示值传递方式捕捉当前的this指针 5.1 函数对象与lambda表达式
函数对象又称为仿函数是可以像函数一样使用的对象。就是在类中重载了operator()运算符的类对象 6. 线程库
6.1 thread类的简单介绍
在C11之前涉及到多线程的问题都是和平台相关的。window和Linux都有自己的接口这就让代码的移植性比较差。C11当中最重要的特性就是对线程进行了支持使C在编程时不需要依赖第三方库
注意 线程是操作系统中的概念线程对象可以关联一个线程用来控制线程以及获取线程的状态 当创建一个线程时 没有提供线程函数该对象实际没有对应任何线程 当创建一个线程对象后并且线程关联线程函数这个线程就被启动。与主线程一起运行。线程函数一般按照如下三种方式提供 函数指针lambda表达式函数对象
6.2 线程函数参数
线程函数参数是以值拷贝的方式拷贝到线程栈空间当中。因此即使线程参数为引用类型在线程当中修改之后也还是不能修改外部实参。因为实际引用的是线程栈中的拷贝不是外部实参
两个线程交替打印奇书偶数
#include iostream
#include condition_variable
#include mutex
#include threadusing namespace std;//支持两个线程交替打印t1打印奇数t2一个打印偶数
int main(){mutex mtx;condition_variable cv;int n 100;int x 1;// 问题1如何保证t1先运行t2阻塞// 问题2如何防止一个线程不断运行thread t1([, n]() {while (true){unique_lockmutex lock(mtx);if (x 100)break;if (x % 2 0) // 偶数就阻塞{cv.wait(lock);}
// cv.wait(lock, [x]() {return x % 2 ! 0; });cout this_thread::get_id() : x endl;x;cv.notify_one();}});thread t2([, n]() {while (true){unique_lockmutex lock(mtx);if (x 100)break;if (x % 2 ! 0) // 奇数就阻塞{cv.wait(lock);}
// cv.wait(lock, [x](){return x % 2 0; });cout this_thread::get_id() : x endl;x;cv.notify_one();}});t1.join();t2.join();return 0;
}7. 包装器
function包装器也叫适配器我们来看看为什么需要包装器本质上是一个类模板也是一个包装器。
包装器的一个使用例子
使用包装器之前的
class Solution {
public:static int evalRPN(vector string tokes){stackint s;for (autostr : tokes){if (str || str - || str * || str /){int right s.top();s.pop();int left s.top();s.pop();switch(str[0]){case :s.push(left right);break;case -:s.push(left - right);break;case *:s.push(left * right);break;case /:s.push(left / right);break;default:break;}}else{s.push(stoi(str));}}}
};使用包装器之后
class Solution {
public:static int evalRPN(vector string tokes){stackint st;mapstring, functionint(int, int) opFuncMap {{, [](int i, int j){return i j;}},{-, [](int i, int j){return i - j;}},{*, [](int i, int j){return i * j;}},{/, [](int i, int j){return i / j;}}};for (auto str : tokes){if (opFuncMap.find(str) ! opFuncMap.end()){int right st.top();st.pop();int left st.top();st.pop();st.push(opFuncMap[str](left, right));}}}
};8.bind
bind函数定义在头文件当中是一个函数模板它就像一个函数包装器适配器接收一个可调用对象生成一个新的可调用对象来“适应”原对象的参数列表。
一般而言我么可以原本接收N个函数的参数的函数fn通过绑定一些参数返回一个接收M个参数M可以大于N
调用bind的一般形式是auto newCallable bind(callable, arg_list)
//表示绑定函数plus 参数分别由调用 func1 的第一二个参数指定
std::functionint(int, int) func1 std::bind(Plus, placeholders::_1,placeholders::_2);