网站续费申请莱芜杂谈 莱芜话题
web/
2025/10/8 19:09:04/
文章来源:
网站续费申请,莱芜杂谈 莱芜话题,装修注意事项及细节,梦幻西游网页版微信区和app互通吗文章目录 C111. 模版的可变参数1.1 模版参数包的使用 2. lambda表达式2.1 Lambda表达式语法捕获列表说明 2.2 lambda的底层 3. 包装器3.1 function包装器3.2 bind 4. 线程库4.1 thread类4.2 mutex类4.3 atomic类4.4 condition_variable类 C11
1. 模版的可变参数 C11支持模版的… 文章目录 C111. 模版的可变参数1.1 模版参数包的使用 2. lambda表达式2.1 Lambda表达式语法捕获列表说明 2.2 lambda的底层 3. 包装器3.1 function包装器3.2 bind 4. 线程库4.1 thread类4.2 mutex类4.3 atomic类4.4 condition_variable类 C11
1. 模版的可变参数 C11支持模版的可变参数可变模版参数比较抽象晦涩我们只探讨其中基础。 template class ...Args // 模版参数包
void ShowList(Args... args) // 函数参数包
{}...表明是可变模版参数称为参数包可以有 [ 0 , N ] [0,N] [0,N] 个模版参数。可变参数的模版函数同样是根据调用情况实例化出多份。
// 展示参数包个数
cout sizeof...(Args) endl;
cout sizeof...(args) endl;1.1 模版参数包的使用
void showlist()
{cout endl;
}templateclass T, class... Args
void show_list(const T val, Args... args)
{cout val ; // 使用第一个参数showlist(args...); // 向下递归传递参数包
}int main()
{showlist();showlist(1);showlist(1, 2);showlist(1, 2, string);return 0;
}参数包可以递归解析。
首先无参调用可直接调用无参版本。其次有参调用的第一个参数会被val获取之后的参数会被参数包获取。使用完第一个参数后可以传参数包下去递归调用。
打印剩余的参数
void showlist()
{cout endl;
}templateclass T, class...Args
void showlist (const T val, Args... args)
{cout __FUNCTION__ -- sizeof...(args)endl;//cout val ;showlist(args...);//cout sizeof...(args) endl;//计算大小//如何解析出可变参数包呢//不能这么玩语法不支持//for (int i 0; i sizeof...(args); i)//{// cout args[i] ;//}
}int main()
{showlist(x, 1,2,string);return 0;
}线程库就是使用可变模版参数支持传递任意个参数。 2. lambda表达式
2.1 Lambda表达式语法
[capture-list](parameters) mutable - return-type { statement }语法组成解释是否省略[capture_list]捕获列表捕捉当前作用域中的变量。分为传值捕捉和引用捕捉不可省略(param_list)参数列表形参默认具有const属性可加mutable去除常属性可省略- ret_type指明返回类型可省略自动推导{}函数体内容不可省略
各部分说明:
capture-list: 捕捉列表该列表总是出现在lambda函数的开始位置编译器根据来。判断接下来的代码是否为lambda函数捕捉列表能够捕捉上下文中的变量供lambda函数使用。(parameters): 参数列表与普通函数的参数列表一致如果不需要参数传递则可以连同()一起省略。mutable: 默认情况下lambda函数总是一个const函数mutable可以取消其常量性。使用该修饰符时参数列表不可省略(即使参数为空)。- return-type: 返回值类型。用追踪返回类型形式声明函数的返回值类型没有返回0值时此部分可省略。返回值类型明确情况下也可省略由编译器对返回类型进行推导。{ statement }: 函数体。在该函数体内除了可以使用其参数外还可以使用所有捕获到的变量。
注意:
在lambda函数定义中参数列表和返回值类型都是可选部分而捕捉列表和函数体可以为空。因此C11中最简单的lambda函数为:0;该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将其赋值给一个变量。
捕获列表说明
[captrue_list] 捕获列表用来捕捉当前作用域前和全局的变量。[]不可省略。
分为传值捕捉和引用捕捉引用捕捉[a, b]。[]表示全引用捕捉[]表示全传值捕捉。捕捉所有能捕捉的变量。[a, ]表示混合捕捉引用捕捉a变量其他变量传值捕捉。但不可重复捕捉。捕捉列表和参数列表的变量默认用const修饰可加mutable解除修饰。
auto func1 [a, b] () {}; // 传值捕捉
auto func2 [a, b] () {}; // 引用捕捉
auto func3 [] () {}; // 全传值捕捉
auto func4 [] () {}; // 全引用捕捉// 混合捕捉
[a, b, ](){}; // 引用捕捉a和b变量其他变量传值捕捉
[, a](){}; // 重复传值捕捉a编译报错注意 父作用域指包含lambda函数的语句块 语法上捕捉列表可由多个捕捉项组成并以逗号分割。
比如[, a, b]以引用传递的方式捕捉变量a和b值传递方式捕捉其他所有变量 [a, this]值传递方式捕捉变量a和this引用方式捕捉其他变量
//Lambda表达式捕捉列表的示例
auto lambda1 [, b]() {std::cout Inside lambda1: a a , b b std::endl;// 可以访问变量a的值但只能以值传递的方式访问而变量b可以以引用传递的方式访问
};捕捉列表不允许变量重复传递否则就会导致编译错误。
比如[, a]已经以值传递方式捕捉了所有变量捕捉a重复
//Lambda表达式捕捉列表中不允许变量重复传递的示例
/// 以下代码将导致编译错误因为变量a已经在捕捉列表中以值传递的方式捕捉了
// auto lambda2 [, a]() {}; // 编译错误重复的捕捉变量a
// auto lambda3 [, ]() {}; //编译错误传值和引用不可以同时存在 在块作用域以外的lambda函数捕捉列表必须为空。 // 在块作用域以外的lambda函数捕捉列表必须为空的示例
int c 20;
auto lambda3 []() {
// 在此lambda函数中只能访问到变量a和b无法访问外部的变量cstd::cout Inside lambda3: a a , b b std::endl;
};lambda表达式之间不能相互赋值即使看起来类型相同 // lambda表达式之间不能相互赋值的示例
// auto lambda4 lambda3;
// 编译错误无法从lambda函数lambda3初始化lambda函数lambda42.2 lambda的底层
lambda表达式不能相互赋值即使看起来类型相同。
auto lamdba []() {};
cout sizeof(lamdba) endl; // 1
cout typeid(lamdba).name() endl; // class int __cdecl main(void)::2::lambda_1// class lambda_fcbffd5ae4b5ac20353abe92769a204flambda表达式最后会被编译器处理成仿函数所以lambda是个空类大小为1。类名不同编译器实现不同但能保证每个lambda表达式类名不同。
看看仿函数和lambda表达式的底层: 3. 包装器
包装器用来包装具有相同特征用途的多个可调用对象便于以统一的形式调用它们。
3.1 function包装器
function包装器也叫做适配器C中的function本质是一个类模版。定义如下
#include functionaltemplate class RetType, class... ArgsType /* 声明返回类型和参数类型 */class functionRet(Args...); // 普通函数
int func(int a, int b) { return a b; }
// 仿函数
struct functor {int operator()(int x, int y) { return x y; }
};
// 非静态成员函数
struct Plus {int plus(int a, int b) { return a b; }
};
// 静态成员函数
struct Sub {static int sub(int a, int b) { return a - b; }
};std::functionint(int, int) f1 f;
std::functionint(int, int) f2 Functor();
std::functionint(Plus, int, int) f3 Plus::plus;
std::functionint(int, int) f4 Sub::sub;封装成员函数时需要注意的点有指定类域、对象参数、加取地址符。
struct Plus {Plus(int i) {}int plus(int a, int b) { return a b; }
};int main()
{functionint(Plus, int, int) f1 Plus::plus;f1(Plus(1), 1, 2);functionint(Plus, int, int) f2 Plus::plus;Plus p(1);f2(p, 1, 2);functionint(Plus*, int, int) f3 Plus::plus;f3(p, 1, 2);functionint(Plus, int, int) f4 Plus::plus;f4(Plus(3), 1, 2);return 0;
}3.2 bind
bind函数也是一个函数包装器本质是一个函数模版。生成一个新的可调用对象来调整一个可调用对象的参数列表。
// without return
template class Func, class... Argsbind(Func fn, Args... args);// with return type
template class Ret, class Func, class... Args bind(Func fn, Args... args);class suber
{
public:suber(int rt) : _rt(rt){}int sub(int a, int b) { return (a - b) * _rt; }
private:int _rt;
};// 通过bind调整参数顺序
functionint(int, int) f1 bind(suber, placeholders::_1, placeholders::_2);
functionint(int, int) f2 bind(suber, placeholders::_2, placeholders::_1);
cout f1(2, 1) endl;
cout f2(1, 2) endl;// 通过bind调整参数个数
functionint(suber, int, int) f3 Sub::sub;
functionint(int, int) f4 bind(Sub::sub, Sub(3), placeholders::_1, placeholders::_2);
cout f3(Sub(1), 2, 1) endl;
cout f4(2, 1) endl;4. 线程库
C11提供了跨平台的具有面向对象特性的线程库线程相关的系统知识在此不作赘述直接讨论线程库的使用。
4.1 thread类
构造函数解释thread() noexcept创建thread对象不执行任何操作thread(Fn fn, Args... args)传入调用对象和参数列表thread(const thread) delete线程对象不可拷贝thread(thread th)线程对象支持移动成员函数解释void join()等待线程void detach()分离线程
关于当前线程的一些操作被放到this_thread类中
this_thread 成员函数解释thread::id get_id () noexcept返回线程IDvoid sleep_for (const chrono::durationRep,Period rel_time)设置休眠时间
vectorthread thds(N); // 线程池
atomicint x 0;for (auto td : thds) {td thread([x, M](int i 0) { while (i M) {cout this_thread::get_id() - x endl; // get_id()this_thread::sleep_for(std::chrono::seconds(1)); // sleep_for()x;}});
}for (auto td : thds) {td.join();
}4.2 mutex类
mutex类封装系统中的互斥锁具体接口如下
mutex解释mutex() noexcept创建互斥锁mutex (const mutex) delete禁止拷贝锁void lock()加锁void unlock()解锁lock_guard解释explicit lock_guard (mutex_type m)构造函数lock_guard (const lock_guard) delete不支持拷贝unique_lock解释explicit unique_lock (mutex_type m)构造函数unique_lock (const unique_lock) delete不支持拷贝void lock()加锁void unlock()解锁
捕获异常并解锁释放资源是不够友好的因此异常时资源的处理交给RAII解决。RAII即资源获取就是初始化是一种管理资源的用法。
本质是将资源封装成类自动调用构造和析构。以达到资源获取自动初始化出作用域自动释放的效果。
利用 RAII 封装的成“智能锁”我们称之为锁守卫lock_guard。
4.3 atomic类
保证自增减的原子性可以使用原子操作。atomic类封装系统原子操作具体接口如下
template class T struct atomic;T fetch_add (T val, memory_order sync memory_order_seq_cst) volatile noexcept; //
T fetch_sub (T val, memory_order sync memory_order_seq_cst) volatile noexcept; // -
T fetch_and (T val, memory_order sync memory_order_seq_cst) volatile noexcept; //
T fetch_or (T val, memory_order sync memory_order_seq_cst) volatile noexcept; // |
T fetch_xor (T val, memory_order sync memory_order_seq_cst) volatile noexcept; // ^
T operator() volatile noexcept; //
T operator--() volatile noexcept; // --无锁算法CAS
Linux原子操作系统调用
4.4 condition_variable类
条件变量是线程同步的一种机制主要包括两个动作等待条件变量挂起条件变量成立运行。
condition_variable解释condition_variable()构造条件变量condition_variable (const condition_variable) delete禁止拷贝条件变量void wait (unique_lockmutex lck)直接等待void wait (unique_lockmutex lck, Predicate pred)指定条件下等待void notify_one() noexcept唤醒单个线程void notify_all() noexcept唤醒多个线程
// wait的实现
template class Predicate
void wait (unique_lockmutex lck, Predicate pred)
{while (!pred()) /* pred()为假进入等待 */wait(lck);
}tex lck) | 直接等待 | |void wait (unique_lock lck, Predicate pred) | 指定条件下等待 | |void notify_one() noexcept | 唤醒单个线程 | |void notify_all() noexcept | 唤醒多个线程 |
// wait的实现
template class Predicate
void wait (unique_lockmutex lck, Predicate pred)
{while (!pred()) /* pred()为假进入等待 */wait(lck);
}模版参数pred是个可调用对象其返回值代表线程是否进入临界区的条件。条件为真停止等待条件为假进入等待。
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/89212.shtml
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!