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

C++11中的可变长模板参数

一、引言

        C++11 引入了变长模板(Variadic Templates),这是模板编程领域的一个重大改进,它允许模板参数的数量是可变的。这一特性极大地增强了模板的灵活性和表达能力,使得开发者能够编写更加通用和强大的代码。变长模板主要通过模板参数包(Template Parameter Packs)和模板函数包(Template Function Packs)来实现。

二、基本语法

2.1 模板参数包

        模板参数包允许模板接受任意数量和类型的模板参数。在模板定义中,使用省略号(...)来指示参数包。参数包可以包含类型参数或值参数。

2.2 类型参数包

        类型参数包用于模板类或模板函数中,表示可以接受任意数量的类型参数。

template<typename... Types>  
class Tuple {  
    // ...  
};  
  
// 使用示例  
Tuple<int, double, std::string> t;

        在这个例子中,Tuple 类模板接受一个类型参数包 Types,它可以包含任意数量的类型。

2.3 值参数包


        值参数包用于模板函数中,表示可以接受任意数量和类型的函数参数。

template<typename... Args>  
void print(Args... args) {  
    // 使用递归模板函数或初始化列表展开参数包  
    // 这里仅作为示例,实际实现需要更复杂的逻辑  
}  
  
// 使用示例  
print(1, 3.14, "Hello");

三、模板参数的展开

方式1:递归展开
#include <iostream>

using namespace std;

// 特例函数,只有一个参数时调用
template <typename T>
void print(const T& item){
    cout << '[' << item << ']' << endl;
}

// 通用函数
template <typename T, typename... Args>
void print(const T& item, Args... args){
    cout << '[' << item << ']';
    print(args...);        // 递归调用
}

int main(){
    print(1, 2.5, "Hello", 'Z');  // 输出:[1][2.5][Hello][Z]
    
    return 0;
}

展开过程:①:print(1, 2.5, "Hello", 'Z') 匹配通用函数,输出 [1] ,再调用 print(2.5, "Hello", 'Z')

                  ②:print(2.5, "Hello", 'Z') 匹配通用函数,输出 [2.5] ,再调用 print("Hello", 'Z')

                  ③:print("Hello", 'Z') 匹配通用函数,输出 [Hello] ,再调用 print( 'Z')

                  ④:print('Z') 匹配特例函数,输出 [Z] ,结束递归。

方式2:初始化列表展开
#include <iostream>

using namespace std;

template <typename... Args>
void print(Args... args){
    (void)initializer_list<int> {
        (cout << '[' << args << ']', 0)...
    };
    
    cout << endl;
}

int main(){
    print(1, 2.5, "Hello", 'Z');  // 输出:[1][2.5][Hello][Z]
    
    return 0;
}

展开过程:

        initializer_list<int>用于初始化一个int类型的列表,(cout << '[' << args << ']', 0)是一个逗号表达式,逗号表达式的优先级最低,其表达式的值为逗号右侧表达式的值,最终得到一个数量和args相同且值都为0的int类型列表,并且将模板参数展开。(void)是为了不产生变量未使用的警告。

方式3:enable_if表达式结合tuple类型展开
#include <iostream>
#include <tuple>
#include <type_traits>

using namespace std;

// 特例函数:当 k 的值和t中元素个数相等时,结束递归
template <size_t k = 0, typename Tuple>
typename enable_if<k == tuple_size<Tuple>::value>::type
format_tuple(const Tuple& t){    
    cout << endl;
}

// 通用函数:当 k 的值小于t中元素个数时,递归调用,输出tuple中的下一个元素
template <size_t k = 0, typename Tuple>
typename enable_if<k < tuple_size<Tuple>::value>::type
format_tuple(const Tuple& t){
    cout << '[' << get<k>(t) << ']';
    
    format_tuple<k + 1>(t);
}

template <typename... Args>
void print(Args... args){
	format_tuple(make_tuple(args...));
}

int main(){
    print(1, 2.5, "Hello", 'Z');  // 输出:[1][2.5][Hello][Z]
    
    return 0;
}

展开过程:①:print(1, 2.5, "Hello", 'Z') 调用format_tuple<0>( tuple(1, 2.5, "Hello", 'Z') ),

                         因为k为0,小于元素的长度4,匹配通用函数,输出[1],然后递归调用

                         format_tuple<1>( tuple(1, 2.5, "Hello", 'Z') )

                  ②:format_tuple<1>( tuple(1, 2.5, "Hello", 'Z') ),1 < 4 输出 [2.5] ,再调用

                         format_tuple<2>( tuple(1, 2.5, "Hello", 'Z') )

                  ③:format_tuple<2>( tuple(1, 2.5, "Hello", 'Z') ),2 < 4 输出 [Hello] ,再调用

                         format_tuple<3>( tuple(1, 2.5, "Hello", 'Z') )

                  ④:format_tuple<3>( tuple(1, 2.5, "Hello", 'Z') ),3 < 4 输出 [Z] ,再调用

                         format_tuple<4>( tuple(1, 2.5, "Hello", 'Z') )

                  ⑤:format_tuple<4>( tuple(1, 2.5, "Hello", 'Z') ),4 == 4,输出endl ,递归结束。

四、小结

        变长模板是 C++11 引入的一项强大功能,它极大地扩展了模板编程的灵活性和表达能力,使得开发者能够编写出更加通用和强大的代码。

附:c++11新增的其他特性


http://www.kler.cn/news/316960.html

相关文章:

  • Linux 线程控制
  • 委托的注册及注销+观察者模式
  • C++容器list底层迭代器的实现逻辑~list相关函数模拟实现
  • 安卓LiveData与MutableLiveData的使用
  • 游戏淡入淡出效果
  • 消息中间件---Kafka
  • 频率增强通道注意力机制(FECAM)学习总结
  • LLMs之Qwen:Qwen2.5的简介、安装和使用方法、案例应用之详细攻略
  • Redisson 总结
  • 二叉树---java---黑马
  • 吴恩达深度学习笔记:卷积神经网络(Foundations of Convolutional Neural Networks)2.1-2.2
  • 【IPV6从入门到起飞】5-5 IPV6+Home Assistant(HACS商店安装)docker版本安装
  • Leetcode3289. 数字小镇中的捣蛋鬼
  • vue中高德地图使用 Marker 标点 - 标点数据快到 1000 时页面卡顿问题解决(已解决 - 多方面原因)+ 海量点功能实现解决
  • 南昌大学-计算机科学与技术专业-预推免-专业课(408)复试面试准备
  • 通信工程学习:什么是MANO管理编排
  • 蓝桥杯嵌入式的学习总结
  • 18 基于51单片机的心率体温监测报警系统(包括程序、仿真、原理图、流程图)
  • helm安装promethues
  • MySQL的缓存策略
  • 数据结构二
  • 影刀RPA实战:网页爬虫之携程酒店数据
  • 文件(打开关闭读写) C语言
  • 面向对象程序设计——mapの简析
  • kettle从入门到精通 第八十七课 ETL之kettle kettle文件上传
  • DevExpress中文教程:如何将WinForms数据网格连接到ASP. NET Core WebAPI服务?
  • 笔记9.18
  • C++速通LeetCode中等第1题-字母异位词分组
  • 在vue中:style 的几种使用方式
  • 【Elasticsearch系列五】Java API