当前位置: 首页 > news >正文

毕设做系统好还是做网站好外贸soho通过网站开发客户

毕设做系统好还是做网站好,外贸soho通过网站开发客户,大学生网页设计作品图片,怎么看网站被降权目录 一、可变参数模板 1.1、可变参数模板的概念 1.2、可变参数模板的定义方式 1.3、如何获取可变参数 二、lambda表达式 2.1、Lamabda表达式定义 2.2、为什么有Lambda 2.3、Lambda表达式的用法 2.4、函数对象与lambda表达式 三、包装器 3.1、function 3.2、bind …目录 一、可变参数模板 1.1、可变参数模板的概念 1.2、可变参数模板的定义方式 1.3、如何获取可变参数 二、lambda表达式 2.1、Lamabda表达式定义 2.2、为什么有Lambda 2.3、Lambda表达式的用法 2.4、函数对象与lambda表达式 三、包装器 3.1、function 3.2、bind 四、线程库 4.1、thread类的简单介绍 4.2、线程函数参数 4.3、原子性操作库(atomic) 4.4、lock_guard与unique_lock     一、可变参数模板 1.1、可变参数模板的概念 可变参数模板是C11新增的最强大的特性之一它对参数高度泛化能够让我们创建可以接受可变参数的函数模板和类模板。 在C11之前类模板和函数模板中只能包含固定数量的模板参数可变模板参数无疑是一个巨大的改进但由于可变参数模板比较抽象因此使用起来需要一定的技巧。在C11之前其实也有可变参数的概念比如printf函数就能够接收任意多个参数但这是函数参数的可变参数并不是模板的可变参数。 1.2、可变参数模板的定义方式 // Args是一个模板参数包args是一个函数形参参数包 // 声明一个参数包Args...args这个参数包中可以包含0到任意个模板参数。template class ...Args void ShowList(Args... args) {// } 上面的参数args前面有省略号所以它就是一个可变模版参数我们把带省略号的参数称为“参数 包”它里面包含了0到NN0个模版参数。我们无法直接获取参数包args中的每个参数的 只能通过展开参数包的方式来获取参数包中的每个参数这是使用可变模版参数的一个主要特 点也是最大的难点即如何展开可变模版参数。由于语法不支持使用args[i]这样方式获取可变 参数所以我们的用一些奇招来一一获取参数包的值。 1.3、如何获取可变参数 方法一、递归函数方式展开参数包 // 递归终止函数 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; } 方法二、逗号表达式展开参数包 这种展开参数包的方式不需要通过递归终止函数是直接在expand函数体中展开的, printarg 不是一个递归终止函数只是一个处理参数包中每一个参数的函数。这种就地展开参数包的方式 实现的关键是逗号表达式。我们知道逗号表达式会按顺序执行逗号前面的表达式。 expand函数中的逗号表达式(printarg(args), 0)也是按照这个执行顺序先执行printarg(args)再得到逗号表达式的结果0。同时还用到了C11的另外一个特性——初始化列 表通过初始化列表来初始化一个变长数组, {(printarg(args), 0)...}将会展开成((printarg(arg1),0), (printarg(arg2),0), (printarg(arg3),0), etc... )最终会创建一个元素值都为0的数组int arr[sizeof...(Args)]。逗号表达式在创建数组的过程中会先执行逗号表达式前面的部分printarg(args)打印出参数也就是说在构造int数组的过程中就将参数包展开了这个数组的目的纯粹是为了在数组构造的过程展开参数包 template class T void PrintArg(T t) {cout t ; } //展开函数 template class ...Args void ShowList(Args... args) {int arr[] { (PrintArg(args), 0)... };cout endl; } int main() {ShowList(1);ShowList(1, A);ShowList(1, A, std::string(sort));return 0; } STL容器中的empalce相关接口函数 cplusplus.com/reference/vector/vector/emplace_back/ cplusplus.com/reference/list/list/emplace_back/ template class... Args void emplace_back (Args... args); 首先我们看到的 emplace系列的接口支持模板的可变参数并且万能引用。 int main() {std::list std::pairint, char mylist;// emplace_back支持可变参数拿到构建pair对象的参数后自己去创建对象// 那么在这里我们可以看到除了用法上和push_back没什么太大的区别mylist.emplace_back(10, a);mylist.emplace_back(20, b);mylist.emplace_back(make_pair(30, c));mylist.push_back(make_pair(40, d));mylist.push_back({ 50, e });for (auto e : mylist)cout e.first : e.second endl;return 0; } int main() {// 下面我们试一下带有拷贝构造和移动构造的bit::string再试试呢// 我们会发现其实差别也不到emplace_back是直接构造了push_back// 是先构造再移动构造其实也还好。std::list std::pairint, bit::string mylist;mylist.emplace_back(10, sort);mylist.emplace_back(make_pair(20, sort));mylist.push_back(make_pair(30, sort));mylist.push_back({ 40, sort});return 0; } 二、lambda表达式 2.1、Lamabda表达式定义 Lambda 表达式lambda expression是一个匿名函数lambda表达式基于数学中的λ演算得名直接对应于其中的lambda抽象lambda abstraction是一个匿名函数即没有函数名的函数。 2.2、为什么有Lambda 在C98中如果想要对一个数据集合中的元素进行排序可以使用std::sort方法。 #include algorithm #include functional int main() {int array[] {4,1,8,5,3,7,0,9,2,6};// 默认按照小于比较排出来结果是升序std::sort(array, arraysizeof(array)/sizeof(array[0]));// 如果需要降序需要改变元素的比较规则std::sort(array, array sizeof(array) / sizeof(array[0]), greaterint());return 0; } 如果待排序元素为自定义类型需要用户定义排序时的比较规则 struct Goods {string _name;  // 名字double _price; // 价格int _evaluate; // 评价Goods(const char* str, double price, int evaluate):_name(str), _price(price), _evaluate(evaluate){} };struct ComparePriceLess {bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;} };struct ComparePriceGreater {bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;} };struct ComparePriceGreater {bool operator()(const Goods gl, const Goods gr){return gl._price gr._price;} };int main() {vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };sort(v.begin(), v.end(), ComparePriceLess());sort(v.begin(), v.end(), ComparePriceGreater()); } 随着C语法的发展人们开始觉得上面的写法太复杂了每次为了实现一个algorithm算法 都要重新去写一个类如果每次比较的逻辑不一样还要去实现多个类特别是相同类的命名 这些都给编程者带来了极大的不便。因此在C11语法中出现了Lambda表达式。 2.3、Lambda表达式的用法 int main() {vectorGoods v { { 苹果, 2.1, 5 }, { 香蕉, 3, 4 }, { 橙子, 2.2, 3 }, { 菠萝, 1.5, 4 } };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._price g2._price; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._evaluate g2._evaluate; });sort(v.begin(), v.end(), [](const Goods g1, const Goods g2){return g1._evaluate g2._evaluate; }); } 2.4、Lambda表达式语法 lambda表达式书写格式 [capture-list] (parameters) mutable - return-type { statement } 1. lambda表达式各部分说明: [capture-list] : 捕捉列表该列表总是出现在lambda函数的开始位置编译器根据[]来 判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda 函数使用。 (parameters)参数列表。与普通函数的参数列表一致如果不需要参数传递则可以 连同()一起省略 mutable默认情况下lambda函数总是一个const函数mutable可以取消其常量 性。使用该修饰符时参数列表不可省略(即使参数为空)。 -returntype返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回 值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推 导。 {statement}函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获 到的变量。 注意 在lambda函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为 空。因此C11中最简单的lambda函数为[]{}; 该lambda函数不能做任何事情。 int main() {// 最简单的lambda表达式, 该lambda表达式没有任何意义[]{}; // 省略参数列表和返回值类型返回值类型由编译器推导为intint a 3, b 4;[]{return a 3; }; // 省略了返回值类型无返回值类型auto fun1 [](int c){b a c; }; fun1(10)couta bendl;// 各部分都很完善的lambda函数auto fun2 [, b](int c)-int{return b a c; }; coutfun2(10)endl;// 复制捕捉xint x 10;auto add_x [x](int a) mutable { x * 2; return a x; }; cout add_x(10) endl; return 0; } 通过上述例子可以看出lambda表达式实际上可以理解为无名函数该函数无法直接调 用如果想要直接调用可借助auto将其赋值给一个变量。 2. 捕获列表说明 捕捉列表描述了上下文中那些数据可以被lambda使用以及使用的方式传值还是传引用。 [var]表示值传递方式捕捉变量var []表示值传递方式捕获所有父作用域中的变量(包括this) [var]表示引用传递捕捉变量var []表示引用传递捕捉所有父作用域中的变量(包括this) [this]表示值传递方式捕捉当前的this指针 注意 a. 父作用域指包含lambda函数的语句块 b. 语法上捕捉列表可由多个捕捉项组成并以逗号分割。 比如[, a, b]以引用传递的方式捕捉变量a和b值传递方式捕捉其他所有变量 [a, this]值传递方式捕捉变量a和this引用方式捕捉其他变量 c. 捕捉列表不允许变量重复传递否则就会导致编译错误。 比如[, a]已经以值传递方式捕捉了所有变量捕捉a重复 d. 在块作用域以外的lambda函数捕捉列表必须为空。 e. 在块作用域中的lambda函数仅能捕捉父作用域中局部变量捕捉任何非此作用域或者非局部变量都会导致编译报错。 f. lambda表达式之间不能相互赋值即使看起来类型相同 void (*PF)(); int main() {auto f1 []{cout hello world endl; };auto f2 []{cout hello world endl; };// 此处先不解释原因等lambda表达式底层实现原理看完后大家就清楚了//f1 f2;   // 编译失败---提示找不到operator()// 允许使用一个lambda表达式拷贝构造一个新的副本auto f3(f2);f3();// 可以将lambda表达式赋值给相同类型的函数指针PF f2;PF();return 0; } 2.4、函数对象与lambda表达式 函数对象又称为仿函数即可以想函数一样使用的对象就是在类中重载了operator()运算符的 类对象。 class Rate { public:Rate(double rate): _rate(rate){}double operator()(double money, int year){ return money * _rate * year;} private:double _rate; };int main() { // 函数对象double rate 0.49;Rate r1(rate);r1(10000, 2);// lamberauto r2 [](double monty, int year)-double{return monty*rate*year; };r2(10000, 2);return 0; } 从使用方式上来看函数对象与lambda表达式完全一样 函数对象将rate作为其成员变量在定义对象时给出初始值即可lambda表达式通过捕获列表可 以直接将该变量捕获到。 三、包装器 3.1、function function包装器 也叫作适配器。C中的function本质是一个类模板也是一个包装器。 函数包装器器其实就是函数指针用了包装器之后函数模板只会实例化一次这里我们了解其用法即可。 可调用对象的类型:函数指针、仿函数(函数对象)、lambda // 函数模板会被实例化多次 templateclass F, class T T useF(F f, T x) {static int count 0;cout count: count endl;cout count: count endl;return f(x); }double func(double i) {return i / 2; }struct Functor {double operator()(double d){return d / 3;} };int main() {// 函数名cout useF(func, 11.11) endl;// 函数对象cout useF(Functor(), 11.11) endl;// lamber表达式cout useF([](double d)-double{ return d / 4; }, 11.11) endl;return 0; }这里我们可以看到静态变量count每次的地址都不一样说明函数模板实例化了3次。 我们可以通过包装器只让函数模板实例化一次 int main() { // 函数名 生成一个函数包装器f1就是函数指针 double (*f1)(double)std::functiondouble(double) f1 func;cout useF(f1, 11.11) endl;// 函数对象std::functiondouble(double) f2 Functor();cout useF(f2, 11.11) endl;// lamber表达式std::functiondouble(double) f3 [](double d)-double{ return d / 4; };cout useF(f3, 11.11) endl;return 0; }可以看到count的值是累加的说明函数模板只实例化了一次 3.2、bind std::bind函数定义在头文件#includefunctional 中是一个函数模板它就像一个函数包装器(适配器)接受一个可 调用对象callable object生成一个新的可调用对象来“适应”原对象的参数列表。一般而 言我们用它可以把一个原本接收N个参数的函数fn通过绑定一些参数返回一个接收M个M 可以大于N但这么做没什么意义参数的新函数。同时使用std::bind函数还可以实现参数顺 序调整等操作。 // 原型如下 template class Fn, class... Args /* unspecified */ bind (Fn fn, Args... args); // with return type (2) template class Ret, class Fn, class... Args /* unspecified */ bind (Fn fn, Args... args); 可以将bind函数看作是一个通用的函数适配器它接受一个可调用对象生成一个新的可调用对 象来“适应”原对象的参数列表。 调用bind的一般形式auto newCallable bind(callable,arg_list); 其中newCallable本身是一个可调用对象arg_list是一个逗号分隔的参数列表对应给定的 callable的参数。当我们调用newCallable时newCallable会调用callable,并传给它arg_list中 的参数。 arg_list中的参数可能包含形如_n的名字其中n是一个整数这些参数是“占位符”表示 newCallable的参数它们占据了传递给newCallable的参数的“位置”。数值n表示生成的可调用对 象中参数的位置_1为newCallable的第一个参数_2为第二个参数以此类推。 // 使用举例 #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() {//表示绑定函数plus 参数分别由调用 func1 的第一二个参数指定std::functionint(int, int) func1 std::bind(Plus, placeholders::_1, placeholders::_2);//auto func1 std::bind(Plus, placeholders::_1, placeholders::_2);//func2的类型为 functionvoid(int, int, int) 与func1类型一样//表示绑定函数 plus 的第一二为 1 2auto  func2 std::bind(Plus, 1, 2);   cout func1(1, 2) endl;cout func2() endl;Sub s;// 绑定成员函数std::functionint(int, int) func3 std::bind(Sub::sub, s, placeholders::_1, placeholders::_2);// 参数调换顺序 std::functionint(int, int) func4 std::bind(Sub::sub, s, placeholders::_2, placeholders::_1);cout func3(1, 2) endl; cout func4(1, 2) endl;return 0; } 总结 td::function包装各种可调用的对象统一可调用对象类型并且指定了参数和返回值类型。 为什么有std:function因为不包装前可调用类型存在很多问题: 1、函数指针类型太复杂不方便使用和理解 2、仿函数类型是一个类名没有指定调用参数和返回值。得去看operator()的实现才能看出来。3、lambda表达式在语法层看不到类型。底层有类型基本都是lambda_uuid也很难看 四、线程库 4.1、thread类的简单介绍 在C11之前涉及到多线程问题都是和平台相关的比如windows和linux下各有自己的接 口这使得代码的可移植性比较差。C11中最重要的特性就是对线程进行支持了使得C在 并行编程时不需要依赖第三方库而且在原子操作中还引入了原子类的概念。要使用标准库中的 线程必须包含 thread 头文件。 注意 1. 线程是操作系统中的一个概念线程对象可以关联一个线程用来控制线程以及获取线程的 状态。 2. 当创建一个线程对象后没有提供线程函数该对象实际没有对应任何线程。 #include thread int main() {std::thread t1;cout t1.get_id() endl;return 0; } get_id()的返回值类型为id类型id类型实际为std::thread命名空间下封装的一个类该类中 包含了一个结构体 // vs下查看 typedef struct { /* thread identifier for Win32 */void *_Hnd; /* Win32 HANDLE */unsigned int _Id; } _Thrd_imp_t; 3. 当创建一个线程对象后并且给线程关联线程函数该线程就被启动与主线程一起运行。 线程函数一般情况下可按照以下三种方式提供        1》 函数指针        2》lambda表达式        3》 函数对象 #include iostream using namespace std; #include thread void ThreadFunc(int a) {cout Thread1 a endl; } class TF { public:void operator()(){cout Thread3 endl;} }; int main() {// 线程函数为函数指针thread t1(ThreadFunc, 10);// 线程函数为lambda表达式thread t2([]{cout Thread2 endl; });// 线程函数为函数对象TF tf;thread t3(tf);t1.join();t2.join();t3.join();cout Main thread! endl;return 0; } 4. thread类是防拷贝的不允许拷贝构造以及赋值但是可以移动构造和移动赋值即将一个 线程对象关联线程的状态转移给其他线程对象转移期间不意向线程的执行。 5. 可以通过jionable()函数判断线程是否是有效的如果是以下任意情况则线程无效        1 采用无参构造函数构造的线程对象        2 线程对象的状态已经转移给其他线程对象        3 线程已经调用jion或者detach结束 4.2、线程函数参数 线程函数的参数是以值拷贝的方式拷贝到线程栈空间中的因此即使线程参数为引用类型在 线程中修改后也不能修改外部实参因为其实际引用的是线程栈中的拷贝而不是外部实参。 #include thread void ThreadFunc1(int x) {x 10; } void ThreadFunc2(int* x) {*x 10; } int main() {int a 10;// 在线程函数中对a修改不会影响外部实参因为线程函数参数虽然是引用方式但其实际 引用的是线程栈中的拷贝thread t1(ThreadFunc1, a);t1.join();cout a endl;// 如果想要通过形参改变外部实参时必须借助std::ref()函数thread t2(ThreadFunc1, std::ref(a);t2.join();cout a endl;// 地址的拷贝thread t3(ThreadFunc2, a);t3.join();cout a endl;return 0; } 注意如果是类成员函数作为线程参数时必须将this作为线程函数参数。 4.3、原子性操作库(atomic) 多线程最主要的问题是共享数据带来的问题(即线程安全)。如果共享数据都是只读的那么没问 题因为只读操作不会影响到数据更不会涉及对数据的修改所以所有线程都会获得同样的数 据。但是当一个或多个线程要修改共享数据时就会产生很多潜在的麻烦。比如 #include iostream using namespace std; #include thread unsigned long sum 0L; void fun(size_t num) {for (size_t i 0; i num; i)sum; } int main() {cout Before joining,sum sum std::endl;thread t1(fun, 10000000);thread t2(fun, 10000000);t1.join();t2.join();cout After joining,sum sum std::endl;return 0; } C98中传统的解决方式可以对共享修改的数据可以加锁保护 #include iostream using namespace std; #include thread #include mutex std::mutex m; unsigned long sum 0L; void fun(size_t num) {for (size_t i 0; i num; i){m.lock();sum;m.unlock();} } int main() {cout Before joining,sum sum std::endl;thread t1(fun, 10000000);thread t2(fun, 10000000);t1.join();t2.join();cout After joining,sum sum std::endl;return 0; } 虽然加锁可以解决但是加锁有一个缺陷就是只要一个线程在对sum时其他线程就会被阻 塞会影响程序运行的效率而且锁如果控制不好还容易造成死锁 因此C11中引入了原子操作。所谓原子操作即不可被中断的一个或一系列操作C11引入 的原子操作类型使得线程间数据的同步变得非常高效。 注意需要使用以上原子操作变量时必须添加头文件#include atomic #include iostream using namespace std; #include thread #include atomic atomic_long sum{ 0 }; void fun(size_t num) {for (size_t i 0; i num; i)sum ;   // 原子操作 } int main() {cout Before joining, sum sum std::endl;thread t1(fun, 1000000);thread t2(fun, 1000000);t1.join();t2.join();cout After joining, sum sum std::endl;return 0; } 在C11中不需要对原子类型变量进行加锁解锁操作线程能够对原子类型变量互斥的 访问。 更为普遍的可以使用atomic类模板定义出需要的任意原子类型。 atmoicT t;    // 声明一个类型为T的原子类型变量t 注意原子类型通常属于资源型数据多个线程只能访问单个原子类型的拷贝因此在C11 中原子类型只能从其模板参数中进行构造不允许原子类型进行拷贝构造、移动构造以及 operator等为了防止意外标准库已经将atmoic模板类中的拷贝构造、移动构造、赋值运算 符重载默认删除掉了。 #include atomic int main() {atomicint a1(0);//atomicint a2(a1);   // 编译失败atomicint a2(0);//a2 a1;               // 编译失败return 0; } 4.4、lock_guard与unique_lock     在多线程环境下如果想要保证某个变量的安全性只要将其设置成对应的原子类型即可即高 效又不容易出现死锁问题。但是有些情况下我们可能需要保证一段代码的安全性那么就只能 通过锁的方式来进行控制。 比如一个线程对变量number进行加一100次另外一个减一100次每次操作加一或者减一之 后输出number的结果要求number最后的值为1. #include thread #include mutex int number 0; mutex g_lock; int ThreadProc1() {for (int i 0; i 100; i){g_lock.lock();number;cout thread 1 : number endl;g_lock.unlock();}return 0; } int ThreadProc2() {for (int i 0; i 100; i){g_lock.lock();--number;cout thread 2 : number endl;g_lock.unlock();}return 0; } int main() {thread t1(ThreadProc1);thread t2(ThreadProc2);t1.join();t2.join();cout number: number endl;system(pause);return 0; } 上述代码的缺陷锁控制不好时可能会造成死锁最常见的比如在锁中间代码返回或者在锁 的范围内抛异常。因此C11采用RAII的方式对锁进行了封装即lock_guard和unique_lock。
http://www.zqtcl.cn/news/931275/

相关文章:

  • 如何做发表文章的网站淮安市建设工程质量监督站网站
  • 做洁净的网站太原便宜做网站的公司
  • 网站设计评级检索标准的网站
  • 做个网站每年都要交域名费吗html静态网页首页模板
  • 网站资源整合与建设wordpress固定链接设置后404
  • 网站历史快照seo推广方法
  • 做淘宝客的的网站有什么要求北京专业网站制作公司
  • 建设网站 知乎个人可以开发app软件吗
  • 网站如何后台管理北京正规网站建设有几种
  • 临沂网站排名高质量的中山网站建设
  • 响应式网站定制开发网络教育全程托管
  • 做网站中的剪辑图片龙岗网站
  • 建设购物网站的意义免费做外贸的网站平台
  • 长沙做电商网站设计重庆观音桥旅游攻略
  • 网站建设的目标与期望动漫设计与制作工资多少
  • 做网站找网站设计公司 长沙
  • 网站维护内容网站代码下载
  • 西安建设主管部门官方网站wordpress返回件
  • 建立免费空间网站南宁seo推广外包
  • 网站初期如何推广用秀米制作h5详细步骤
  • 做网站需要执照嘛开发 网站 团队
  • 怎么提交网站关键词包头人脸检测系统
  • 哪个网站开发是按月付费的婚纱摄影建设网站的目的
  • 站长之家app简单网站制作步骤
  • 网站开发与桌面应用开发wordpress if include
  • 网站怎么做预约小程序江苏省工程建设招标网站
  • python做网站有什么弊端专业做网带
  • 浙江建设工程考试网站wordpress等模版比较
  • seo网站论文高端疫苗
  • 山东省城乡住房和建设厅网站首页贵阳网站建设技术托管