跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++

C++11 新特性:可变参数模板、类功能与 STL 变化

综述由AI生成C++11 引入可变参数模板支持零或多个参数,通过省略号 (...) 进行包扩展。展示了递归终止条件和函数参数展开两种实现方式。STL 新增 emplace 系列接口支持原地构造,减少临时对象开销。涉及移动构造、赋值、default/delete 声明及包装器 function 和 bind 的使用。

HadoopMan发布于 2026/3/29更新于 2026/6/716 浏览
C++11 新特性:可变参数模板、类功能与 STL 变化

可变参数模板

基本语法及原理

  • C++11 支持可变参数模板,即支持可变数量参数的函数模板和类模板。可变数目的参数称为参数包,存在两种参数包:模板参数包(表示零或多个模板参数);函数参数包(表示零或多个函数参数)。
  • template <class ...Args> void Func(Args... args) {}
  • template <class ...Args> void Func(Args&... args) {}
  • template <class ...Args> void Func(Args&&... args) {}
  • 使用省略号来指出一个模板参数或函数参数表示一个包。在模板参数列表中,class... 或 typename... 指出接下来的参数表示零或多个类型列表;在函数参数列表中,类型名后面跟 ... 指出接下来表示零或多个形参对象列表。函数参数包可以用左值引用或右值引用表示,每个参数实例化时遵循引用折叠规则。
  • 可变参数模板的原理跟普通模板类似,本质还是去实例化对应类型和个数的多个函数。
  • 可以使用 sizeof... 运算符计算参数包中参数的个数。
template <class ...Args> void Print(Args&&... args) { 
    cout << sizeof...(args) << endl; 
}
int main() { 
    double x = 2.2; 
    Print(); // 包里有 0 个参数 
    Print(1); // 包里有 1 个参数 
    Print(1, string("xxxxx")); // 包里有 2 个参数 
    Print(1.1, string("xxxxx"), x); // 包里有 3 个参数 
    return 0; 
} 

原理说明:

  1. 编译本质结合引用折叠规则实例化出以下四个函数:
    • void Print();
    • void Print(int&& arg1);
    • void Print(int&& arg1, string&& arg2);
void Print(double&& arg1, string&& arg2, double& arg3);
  • 更本质地看,没有可变参数模板时,需要实现多个函数模板才能支持该功能。有了可变参数模板,是在类型泛化基础上叠加数量变化,让泛型编程更灵活。
  • 文章配图

    包扩展

    对于一个参数包,除了能计算参数个数,唯一能做的操作就是扩展它。当扩展一个包时,需要提供用于每个扩展元素的模式。扩展一个包就是将它分解为构成的元素,对每个元素应用模式,获得扩展后的列表。通过在模式的右边放一个省略号 (...) 来触发扩展操作。

    C++ 还支持更复杂的包扩展,直接将参数包依次展开作为实参给一个函数去处理。

    不支持用下面的方式去进行包扩展:

    // 可变模板参数 // 参数类型可变 // 参数个数可变 // 打印参数包内容
    template <class ...Args> void Print(Args... args) {
        // 可变参数模板编译时解析
        // 下面是运行获取和解析,所以不支持这样用
        cout << sizeof...(args) << endl;
        for (size_t i = 0; i < sizeof...(args); i++) {
            cout << args[i] << " ";
        }
        cout << endl;
    }
    

    见下面使用递归的一种包扩展的方式:

    方式一

    void ShowList() { 
        // 编译器时递归的终止条件,参数包是 0 个时,直接匹配这个函数 
        cout << endl; 
    }
    template <class T, class ...Args> void ShowList(T x, Args... args) { 
        cout << x << " "; 
        // args 是 N 个参数的参数包
        // 调用 ShowList,参数包的第一个传给 x,剩下 N-1 传给第二个参数包 
        ShowList(args...); 
    }
    // 编译时递归推导解析参数
    template <class ...Args> void Print(Args... args) { 
        ShowList(args...); 
    }
    int main() { 
        Print(1, string("xxxxx"), 2.2); 
        return 0; 
    } 
    

    调用时本质: 编译器将可变参数模板通过模式的包扩展,编译器推导的以下三个重载函数:

    • void ShowList(double x) -> { cout << x << " "; ShowList(); }
    • void ShowList(string x, double z) -> { cout << x << " "; ShowList(z); }
    • void ShowList(int x, string y, double z) -> { cout << x << " "; ShowList(y, z); }
    • void Print(int x, string y, double z) -> { ShowList(x, y, z); }

    文章配图 图一

    方式二

    template <class T> const T & GetArg(const T & x) { 
        cout << x << " "; 
        return x; 
    }
    template <class ...Args> void Arguments(Args... args) { }
    template <class ...Args> void Print(Args... args) { 
        // 注意 GetArg 必须返回或者到的对象,这样才能组成参数包给 Arguments
        Arguments(GetArg(args)...); 
    }
    

    解释: 本质可以理解为编译器编译时,包的扩展模式将上面的函数模板扩展实例化为下面的函数:

    • void Print(int x, string y, double z) -> { Arguments(GetArg(x), GetArg(y), GetArg(z)); }

    文章配图

    emplace 系列接口

    • template <class ...Args> void emplace_back(Args&&... args);
    • template <class ...Args> iterator emplace(const_iterator position, Args&&... args);

    C++11 以后 STL 容器新增了 emplace 系列的接口。emplace 系列的接口均为模板可变参数,功能上兼容 push 和 insert 系列,但是 emplace 还支持新玩法。假设容器为 container,emplace 还支持直接插入构造 T 对象的参数,这样有些场景会更高效一些,可实现原地构造,避免临时对象开销。

    目录

    1. 可变参数模板
    2. 基本语法及原理
    3. 包扩展
    4. 方式一
    5. 方式二
    6. emplace 系列接口
    • 💰 8折买阿里云服务器限时8折了解详情
    • Magick API 一键接入全球大模型注册送1000万token查看
    • 🤖 一键搭建Deepseek满血版了解详情
    • 一键打造专属AI 智能体了解详情
    极客日志微信公众号二维码

    微信扫一扫,关注极客日志

    微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

    更多推荐文章

    查看全部
    • QClaw 本地化 AI 个人助手平台完全指南
    • OpenClaw 智能体实战:从零搭建你的第一个 AI 员工
    • macOS 清理:用免费开源工具 Pearcleaner 彻底卸载应用
    • 易语言子程序高级应用:递归、回调与参数设计实战
    • 2024 人工智能大模型发展现状、应用案例与总结展望
    • Vue3 组合式函数(Composables)实战:逻辑拆分与封装
    • AI Agent 技术架构与落地实践指南
    • NVIDIA Jetson Thor T5000 解析:产品谱系、架构性能与落地路径
    • Windows 11 配置 CUDA 版 llama.cpp 实现 GGUF 模型本地聊天
    • 树莓派 Python PWM 控制 LED 亮度教程
    • C#设计模式:工厂方法模式详解
    • C++ 语言基础与进阶教程
    • 火山引擎豆包大模型助力电商 AIGC 智能化升级
    • Chrome 插件开发指南:从 Web 到扩展及实战
    • 基于 Coze 工作流与 Sora2 的 AI 漫剧生成方法
    • Go Web 开发核心理论与实践
    • DFT 中的片上时钟控制器(OCC)架构设计与插入规则
    • macOS 使用中科大或清华镜像快速安装 Homebrew 教程
    • 机器人 DH 参数模型与正运动学
    • SimPO 大模型对齐算法原理与 ms-swift 实践

    相关免费在线工具

    • Base64 字符串编码/解码

      将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

    • Base64 文件转换器

      将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

    • Markdown转HTML

      将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

    • HTML转Markdown

      将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online

    • JSON 压缩

      通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online

    • JSON美化和格式化

      将JSON字符串修饰为友好的可读格式。 在线工具,JSON美化和格式化在线工具,online