广告
返回顶部
首页 > 资讯 > 后端开发 > 其他教程 >C++可变参数模板的展开方式是什么
  • 867
分享到

C++可变参数模板的展开方式是什么

2023-06-29 21:06:24 867人浏览 独家记忆
摘要

这篇文章主要讲解了“c++可变参数模板的展开方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++可变参数模板的展开方式是什么”吧!可变参数模板(variadic templates

这篇文章主要讲解了“c++可变参数模板的展开方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++可变参数模板的展开方式是什么”吧!

可变参数模板(variadic templates)是C++11新增的强大的特性之一,它对模板参数进行了高度泛化,能表示0到任意个数、任意类型的参数。相比C++98/03这些类模版和函数模版中只能含固定数量模版参数的“老古董”,可变模版参数无疑是一个巨大的进步。

如果是刚接触可变参数模板可能会觉得比较抽象,使用起来会不太顺手,使用可变参数模板时通常离不开模板参数的展开,所以本文来列举一些常用的模板展开方式,帮助我们来对可变参数模板有一个初步的了解。

可变参数模板的定义

可变参数模板和普通模板的定义类似,在写法上需要在 typenameclass 后面带上省略号...,以下为一个常见的可变参数函数模板:

template <class... T>void func(T... args){    //...}

上面这个函数模板的参数 args 前面有省略号,所以它就是一个被称为模板参数包(template parameter pack)的可变模版参数,它里面包含了0到N个模版参数,而我们是无法直接获取 args 中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这也是本文要重点总结的内容。

参数包的展开

参数包展开的方式随着c++语言的发展也在与时俱进,我们以实现一个可变参格式化打印函数为例,列举一些常用的方式:

递归函数方式展开

#include <iOStream>void FORMatPrint(){    std::cout << std::endl;}template <class T, class ...Args>void FormatPrint(T first, Args... args){   std::cout << "[" << first << "]";   FormatPrint(args...);}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("Good", 2, "hello", 4, 110);   return 0;}

这种递归展开的方式与递归函数的定义是一样的,需要递归出口和不断调用自身,仔细看看这个函数模板是不是都满足啦?递归出口就是这个无模板参数的 FormatPrint,并且在有参模板中一直在调用自身,递归调用的过程时这样的 FormatPrint(4,3,2,1) -> FormatPrint(3,2,1) -> FormatPrint(2,1) -> FormatPrint(1) -> FormatPrint(),输出内容如下:

>albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out[1][2][3][4][good][2][hello][4][110]

逗号表达式展开

#include <iostream>template <class ...Args>void FormatPrint(Args... args){   (void)std::initializer_list<int>{ (std::cout << "[" << args << "]", 0)... };   std::cout << std::endl;}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("good", 2, "hello", 4, 110);   return 0;}

这种方式用到了C++11的新特性初始化列表(Initializer lists)以及很传统的逗号表达式,我们知道逗号表达式的优先级最低,(a, b) 这个表达式的值就是 b,那么上述代码中(std::cout << "[" << args << "]", 0)这个表达式的值就是0,初始化列表保证其中的内容从左往右执行,args参数包会被逐步展开,表达式前的(void)是为了防止变量未使用的警告,运行过后我们就得到了一个N个元素为0的初始化列表,内容也被格式化输出了:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out[1][2][3][4][good][2][hello][4][110]

说到这顺便提一下,可以使用sizeof...(args)得到参数包中参数个数。

enable_if方式展开

#include <iostream>#include <tuple>#include <type_traits>template<std::size_t k = 0, typename tup>typename std::enable_if<k == std::tuple_size<tup>::value>::type FormatTuple(const tup& t){    std::cout << std::endl;}template<std::size_t k = 0, typename tup>typename std::enable_if<k < std::tuple_size<tup>::value>::type FormatTuple(const tup& t){    std::cout << "[" << std::get<k>(t) << "]";    FormatTuple<k + 1>(t);}template<typename... Args>void FormatPrint(Args... args){    FormatTuple(std::make_tuple(args...));}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("good", 2, "hello", 4, 110);   return 0;}

C++11的enable_if常用于构建需要根据不同的类型的条件实例化不同模板的时候。顾名思义,当满足条件时类型有效。可作为选择类型的小工具,其广泛的应用在 C++ 的模板元编程(meta programming)之中,利用的就是SFINAE原则,英文全称为Substitution failure is not an error,意思就是匹配失败不是错误,假如有一个特化会导致编译时错误,只要还有别的选择,那么就无视这个特化错误而去选择另外的实现,这里的特化概念不再展开,感兴趣可以自行了解,后续可以单独总结一下。

在上面的代码实现中,基本思路是先将可变模版参数转换为std::tuple,然后通过递增参数的索引来选择恰当的FormatTuple函数,当参数的索引小于tuple元素个数时,会不断取出当前索引位置的参数并输出,当参数索引等于总的参数个数时调用另一个模板重载函数终止递归,编译运行输入以下内容:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++11albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out[1][2][3][4][good][2][hello][4][110]

折叠表达式展开(c++17)

#include <iostream>template<typename... Args>void FormatPrint(Args... args){    (std::cout << ... << args) << std::endl;}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("good", 2, "hello", 4, 110);   return 0;}

折叠表达式(Fold Expressions)是C++17新引进的语法特性,使用折叠表达式可以简化对C++11中引入的参数包的处理,可以在某些情况下避免使用递归,更加方便的展开参数,如上述代码中展示的这样可以方便的展开参数包,不过输出的内容和之前的有些不一样:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++17albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out1234good2hello4110

对比结果发现缺少了格式化的信息,需要以辅助函数的方式来格式化:

#include <iostream>template<typename T>string format(T t) {    std::stringstream ss;    ss << "[" << t << "]";    return ss.str();}template<typename... Args>void FormatPrint(Args... args){    (std::cout << ... << format(args)) << std::endl;}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("good", 2, "hello", 4, 110);   return 0;}

这次格式化内容就被加进来了:

albert@home-pc:/mnt/d/data/cpp/testtemplate$ g++ testtemplate.cpp --std=c++17albert@home-pc:/mnt/d/data/cpp/testtemplate$ ./a.out[1][2][3][4][good][2][hello][4][110]

这样好像还是有点麻烦,我们可以把折叠表达式和逗号表达式组合使用,这样得到的代码就简单多啦,也能完成格式化输出的任务:

#include <iostream>template<typename... Args>void FormatPrint(Args... args){    (std::cout << ... << (std::cout << "[" << args, "]")) << std::endl;}int main(void){   FormatPrint(1, 2, 3, 4);   FormatPrint("good", 2, "hello", 4, 110);   return 0;}

感谢各位的阅读,以上就是“C++可变参数模板的展开方式是什么”的内容了,经过本文的学习后,相信大家对C++可变参数模板的展开方式是什么这一问题有了更深刻的体会,具体使用情况还需要大家实践验证。这里是编程网,小编将为大家推送更多相关知识点的文章,欢迎关注!

--结束END--

本文标题: C++可变参数模板的展开方式是什么

本文链接: https://www.lsjlt.com/news/326402.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • C++可变参数模板的展开方式是什么
    这篇文章主要讲解了“C++可变参数模板的展开方式是什么”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“C++可变参数模板的展开方式是什么”吧!可变参数模板(variadic templates...
    99+
    2023-06-29
  • 浅析C++可变参数模板的展开方式
    目录前言可变参数模板的定义参数包的展开递归函数方式展开逗号表达式展开enable_if方式展开折叠表达式展开(c++17)总结前言 可变参数模板(variadic templates...
    99+
    2022-11-13
  • C++11中的可变参数模板/lambda表达式
    目录1.可变参数模板递归函数方式展开参数包逗号表达式展开参数包2.lambda表达式先来看看lambda表达式的例子:lambda表达式语法1.可变参数模板 C++11的新特性可变参...
    99+
    2023-03-24
    C++11 lambda表达式 C++11 可变参数模板
  • C++新标准难点解析之什么是可变模板参数
    本篇内容介绍了“C++新标准难点解析之什么是可变模板参数”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成! 前言C++的新特性--可变...
    99+
    2023-06-15
  • C++11中的可变参数模板和lambda表达式怎么使用
    本篇内容介绍了“C++11中的可变参数模板和lambda表达式怎么使用”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!1.可变参数模板C++1...
    99+
    2023-07-05
  • C++模板参数的具体概念是什么
    这篇文章给大家介绍C++模板参数的具体概念是什么,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。C++编程语言是一个功能强大的计算机应用语言,它的出现在一定程度上大大降低了开发人员的负担,提高了开发效率。我们在这里先来了...
    99+
    2023-06-17
  • c++类函数作为模板参数实现的方法是什么
    今天小编给大家分享一下c++类函数作为模板参数实现的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。需求背景DB操作...
    99+
    2023-07-05
  • C语言中可变参数的原理是什么
    C语言中可变参数的原理是什么,相信很多没有经验的人对此束手无策,为此本文总结了问题出现的原因和解决方法,通过这篇文章希望你能解决这个问题。var_list可变参数介绍VA_LIST 是在C语言中解决变参问题的一组宏,原型:typedef&n...
    99+
    2023-06-15
  • C++非类型类模板参数的基本概念是什么
    C++非类型类模板参数的基本概念是什么,很多新手对此不是很清楚,为了帮助大家解决这个难题,下面小编将为大家详细讲解,有这方面需求的人可以来学习下,希望你能有所收获。C++编程语言已经出现就立即引起了开发人员的注意,它具有C语言的所用功能,并...
    99+
    2023-06-17
  • C语言可变参数使用与内存管理的方法是什么
    这篇“C语言可变参数使用与内存管理的方法是什么”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“C语言可变参数使用与内存管理的方...
    99+
    2023-07-04
  • C# WPF数据绑定模板化操作的方法是什么
    今天小编给大家分享一下C# WPF数据绑定模板化操作的方法是什么的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。具体...
    99+
    2023-06-26
  • smarty模板的数据变量有哪些以及调用方法是什么
    本篇内容主要讲解“smarty模板的数据变量有哪些以及调用方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“smarty模板的数据变量有哪些以及调用方法是什么”吧! 定义:模板变...
    99+
    2023-06-07
  • R语言数据可视化tidyr与ggplot2多个变量分层展示的实现方法是什么
    本篇内容主要讲解“R语言数据可视化tidyr与ggplot2多个变量分层展示的实现方法是什么”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“R语言数据可视化tidyr与ggplot2多个变量分层展...
    99+
    2023-06-25
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作