c++中的可变参数模板(variadic templates)怎么用_c++模板编程黑魔法【C++11】
技术百科
冰火之心
发布时间:2026-01-01
浏览: 次 可变参数模板是C++11核心特性,支持任意数量和类型的模板参数,依赖类型参数包(class.../typename...)和函数参数包(Args... args),通过递归展开或折叠表达式(如f(args...)、(args, ...))实现类型安全的泛型编程。
可变参数模板是 C++11 引入的核心特性之一,它让模板能接受任意数量、任意类型的参数,是实现类型安全的泛型容器、完美转发、日志函数、元编程等高级功能的基础。用得好,代码简洁又高效;用得不熟,容易陷入递归展开和参数包(parameter pack)的迷雾中。
基础写法:声明与展开参数包
可变参数模板的关键在于 参数包(template parameter pack) 和 函数参数包(function parameter pack),以及它们的展开方式。
- 声明模板时用
class...或typename...表示类型参数包,如template - 函数参数列表中用
Args... args表示值参数包 - 展开必须在支持“逗号表达式上下文”的地方进行,比如函数调用、初始化列表、基类列表等
- 最常用展开方式:
f(args...)(调用时展开)、{f(args)...}(C++17 折叠表达式)、int arr[] = {g(args)...}(初始化数组)
递归展开:处理参数包的经典模式
由于不能直接对参数包做循环,传统做法是靠“头尾分离”+递归终止来逐个处理。典型结构:
- 先写一个只接受一个参数的重载(递归终点),例如
void print(T t) { std::cout - 再写一个可变参数版本,取出第一个参数(
first),其余递归调用自身:templatevoid print(T first, Rest... rest) { std::cout - 注意:递归调用
print(rest...)会自动推导剩余参数类型,直到
只剩一个参数触发终点重载
折叠表达式(C++17):一行搞定多数聚合操作
告别繁琐递归!C++17 引入折叠表达式,语法简洁且高效:
- 一元右折叠:
(args && ...)等价于args1 && args2 && args3 && ... - 一元左折叠:
(... && args)同样效果,但结合律不同(对&&/||无影响) - 二元折叠:
(init + ... + args)展开为init + arg1 + arg2 + ... - 实用例子:安全打印所有参数
((std::cout —— 利用逗号表达式顺序求值
完美转发与参数包转发:保持值类别不变
配合 std::forward 和万能引用(T&&),可变参数模板能真正实现“原样转发”:
- 写法:
templatevoid wrapper(Args&&... args) { func(std::forward(args)...); } - 关键点:
Args&&是万能引用,std::forward(args)恢复原始值类别(lvalue/rvalue) - 这是
std::make_unique、std::thread构造等标准库功能的底层支撑
基本上就这些。可变参数模板不是炫技工具,而是构建现代 C++ 基础设施的砖块——理解参数包、掌握展开时机、善用折叠与转发,就能把黑魔法变成日常生产力。
# 这是
# 能把
# 第一个
# 关键在于
# 最常用
# 循环
# 递归
# c++
# int
# void
# class
# 泛型
# function
# 时用
# print
# 值参数
# 只剩
# 可变参数
# 用得
# 不熟
相关栏目:
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
AI推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
SEO优化<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
技术百科<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
谷歌推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
百度推广<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
网络营销<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
案例网站<?muma echo $count; ?>
】
<?muma
$count = M('archives')->where(['typeid'=>$field['id']])->count();
?>
【
精选文章<?muma echo $count; ?>
】
相关推荐
- PHP主流架构怎么集成Redis缓存_配置步骤【方
- 本地php环境打开php文件直接下载_浏览器解析p
- 如何使用Golang实现容器安全扫描_Golang
- Python解释执行模型_字节码流程说明【指导】
- Win11怎么开启上帝模式_创建Windows 1
- LINUX怎么查看进程_LINUX ps命令查看运
- Win10怎样卸载TeamViewer_Win10
- Win11任务栏天气怎么关闭 Win11隐藏天气小
- 一文详解网站被黑客入侵挂马解决办法
- 如何在Golang中使用encoding/gob序
- 如何使用Golang编写单元测试_创建Test函数
- 如何使用Golang实现容器健康检查_监控和自动重
- Windows10蓝屏SYSTEM_SERVICE
- 如何在Windows中创建新的用户账户?(标准与管
- 如何使用 Selenium 正确获取篮球参考网站球
- Mac怎么设置鼠标滚动速度_Mac鼠标设置详细参数
- PhpStorm怎么调试PHP代码_PhpStor
- Win11声音忽大忽小怎么办 Win11音频增强功
- 如何在包含多值的列中精准搜索指定演员?
- 如何在Golang中优化文件读写性能_使用缓冲和并
- Win11怎么更改账户头像_Windows 11自
- 如何用正则与预处理高效拦截带干扰符的恶意域名
- Python高性能计算项目教程_NumPyCyth
- c++ stringstream用法详解_c++字
- 网站内页做seo排名怎么做?
- windows 10应用商店区域怎么改_windo
- Win11怎么更改输入法顺序_Win11调整语言首
- LINUX如何删除用户和用户组_Linux use
- php订单日志怎么按金额排序_php按订单金额排序
- Win11键盘快捷键大全_Windows 11常用
- 电脑无法识别U盘怎么办 Windows磁盘管理与驱
- Windows驱动无法加载错误解决方法_驱动签名验
- Python大型项目拆分策略_模块化解析【教程】
- Win11怎么关闭定位服务_保护Win11位置隐私
- Windows 11无法安全删除U盘提示设备正在使
- Win10如何更改用户账户控制_Windows10
- Mac系统更新下载慢或失败怎么办_解决macOS升
- php订单日志怎么按状态筛选_php筛选不同状态订
- Win11怎么查看局域网电脑_Windows 11
- Python文本编码与解码_跨平台解析说明【指导】
- 如何使用Golang实现函数指针_函数变量与回调示
- Windows 10怎么把任务栏放在屏幕上方_Wi
- XSLT怎么生成动态的HTML属性名和标签名
- Python对象比较与排序_集合使用说明【指导】
- C++中引用和指针有什么区别?(代码说明)
- 如何使用Golang管理模块版本_Golanggo
- 如何在Golang中引入测试模块_Golang测试
- 如何在 PHP 单元测试中正确模拟带方法的图像处理
- Win11怎么关闭自动调节亮度_Windows11
- 如何使用Golang sync.Map实现并发安全

只剩一个参数触发终点重载
QQ客服