元素码农
基础
UML建模
数据结构
算法
设计模式
网络
TCP/IP协议
HTTPS安全机制
WebSocket实时通信
数据库
sqlite
postgresql
clickhouse
后端
rust
go
java
php
mysql
redis
mongodb
etcd
nats
zincsearch
前端
浏览器
javascript
typescript
vue3
react
游戏
unity
unreal
C++
C#
Lua
App
android
ios
flutter
react-native
安全
Web安全
测试
软件测试
自动化测试 - Playwright
人工智能
Python
langChain
langGraph
运维
linux
docker
工具
git
svn
🌞
🌙
目录
▶
C++基础
▶
类型系统
基本数据类型
类型推导
类型转换
▶
编译模型
翻译单元
ODR规则
头文件与实现分离
▶
作用域与生命周期
存储期类型
RAII机制
对象构造与析构
▶
面向对象编程
▶
类设计
成员访问控制
特殊成员函数
友元机制
▶
继承体系
虚函数表
多重继承
虚继承
▶
多态实现
动态绑定
RTTI机制
类型擦除
▶
模板与泛型编程
▶
模板基础
函数模板
类模板
可变参数模板
▶
模板元编程
SFINAE
类型萃取
编译期计算
▶
概念与约束
requires表达式
概念定义
约束模板
▶
内存模型
▶
内存管理
堆与栈
智能指针
移动语义
▶
对象模型
成员布局
虚函数实现
空基类优化
▶
并发内存
内存顺序
原子操作
内存屏障
▶
标准库核心
▶
容器
序列容器
关联容器
无序容器
▶
迭代器
迭代器类别
迭代器适配器
范围迭代
▶
函数对象
函数包装器
绑定表达式
lambda实现
发布时间:
2025-03-23 09:59
↑
☰
# C++可变参数模板 本文将详细介绍C++的可变参数模板机制,包括其语法、实现原理以及最佳实践。通过理解可变参数模板,我们可以编写更加灵活和通用的模板代码。 ## 可变参数模板概述 可变参数模板允许模板接受任意数量的参数: 1. 基本概念 - 模板参数包 - 函数参数包 - 包展开 2. 主要特点 - 类型安全 - 编译期展开 - 零运行时开销 ## 基本语法 ```cpp // 可变参数函数模板 template<typename... Args> void print(Args... args) { (std::cout << ... << args) << '\n'; } // 可变参数类模板 template<typename... Types> class Tuple; // 递归特化 template<typename First, typename... Rest> class Tuple<First, Rest...> : private Tuple<Rest...> { First first_; }; // 特化结束 template<> class Tuple<> {}; ``` ## 参数包展开 ```cpp // 递归展开 template<typename T> void print_single(const T& t) { std::cout << t << ' '; } template<typename First, typename... Rest> void print_recursive(const First& first, const Rest&... rest) { print_single(first); if constexpr (sizeof...(rest) > 0) { print_recursive(rest...); } } // 折叠表达式(C++17) template<typename... Args> void sum(Args... args) { // 一元右折叠 auto result = (args + ...); // 二元左折叠 auto result2 = (... + args); // 带初始值的折叠 auto result3 = (0 + ... + args); } ``` ## 完美转发 ```cpp // 通用工厂函数 template<typename T, typename... Args> std::unique_ptr<T> make_unique(Args&&... args) { return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); } // 可变参数构造函数 class Widget { public: template<typename... Args> Widget(Args&&... args) : data_(std::forward<Args>(args)...) {} private: std::vector<int> data_; }; ``` ## 可变参数模板应用 1. 异构容器 ```cpp // 类型安全的异构容器 template<typename... Types> class Variant { public: template<typename T> bool is() const { return (std::is_same_v<T, Types> || ...); } template<typename T> T& get() { if (!is<T>()) { throw std::bad_cast(); } return *reinterpret_cast<T*>(storage_); } private: alignas(Types...) unsigned char storage_[std::max({sizeof(Types)...})]; }; ``` 2. 委托构造 ```cpp class Logger { public: template<typename... Args> void log(const char* format, Args&&... args) { char buffer[1024]; snprintf(buffer, sizeof(buffer), format, std::forward<Args>(args)...); writeToLog(buffer); } private: void writeToLog(const char* message) { // 写入日志 } }; ``` ## 最佳实践 1. 参数包处理 - 使用折叠表达式 - 递归展开 - sizeof...运算符 ```cpp // 参数包处理示例 template<typename... Args> size_t count_args(Args... args) { return sizeof...(args); } template<typename... Args> bool all_of(Args... args) { return (... && args); } template<typename... Args> bool any_of(Args... args) { return (... || args); } ``` 2. 类型安全 - 编译期检查 - 概念约束 - 静态断言 ```cpp // 类型安全示例 template<typename T, typename... Args> concept AllConvertible = (std::convertible_to<Args, T> && ...); template<typename T, typename... Args> requires AllConvertible<T, Args...> void process(Args... args) { std::vector<T> vec{static_cast<T>(args)...}; } ``` 3. 性能优化 - 避免递归实现 - 利用编译期优化 - 减少模板实例化 ## 注意事项 1. 编译开销 - 模板实例化数量 - 编译时间 - 代码膨胀 2. 调试难度 - 错误信息复杂 - 参数包展开追踪 - 类型推导问题 3. 使用限制 - 参数包位置 - 展开语法 - 模板参数推导 ## 总结 可变参数模板是C++11引入的强大特性,它允许我们编写能处理任意数量参数的模板代码。通过参数包展开、完美转发等机制,我们可以实现灵活且类型安全的泛型代码。在使用可变参数模板时,应该注意编译开销和调试难度,并遵循最佳实践来确保代码的可维护性和效率。