C++11可变参数模板(typename... Args模板参数包或class... Args)(Args... args函数参数包)(递归展开与参数包展开(只支持C++17))

这篇具有很好参考价值的文章主要介绍了C++11可变参数模板(typename... Args模板参数包或class... Args)(Args... args函数参数包)(递归展开与参数包展开(只支持C++17))。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++可变参数

C++可变参数是指函数的参数个数是可变的,可以在函数定义时不确定参数的个数,需要在函数体内通过特定的语法来处理这些参数。C++11标准引入了新的可变参数模板,使得可变参数的处理更加方便和灵活。在函数定义时,可以使用省略号(…)来表示可变参数,然后通过va_list、va_start、va_arg和va_end等宏来访问这些参数。例如,下面是一个简单的可变参数函数的示例:

#include <iostream>
#include <cstdarg>

using namespace std;

double average(int count, ...)
{
    va_list ap;
    int i;
    double sum = 0;

    va_start(ap, count); // 初始化可变参数列表

    for (i = 0; i < count; i++)
    {
        sum += va_arg(ap, double); // 访问可变参数列表中的参数
    }

    va_end(ap); // 结束可变参数列表

    return sum / count;
}

int main()
{
    cout << average(3, 1.0, 2.0, 3.0) << endl; // 输出平均值
    return 0;
}

c++ 参数包,C/C++,c++,开发语言,算法

在上面的示例中,average函数的第一个参数count表示可变参数的个数,后面的省略号表示可变参数列表。在函数体内,首先使用va_start宏初始化可变参数列表,然后使用va_arg宏访问可变参数列表中的参数,最后使用va_end宏结束可变参数列表。

C++可变参数具体可参见:C语言函数参数中的三个点(三点 “…”)是干什么用的?(可变参数)<stdarg.h>、va_start 宏、va_arg 宏、va_end 宏

C++可变参数模板

C++11标准引入了新的可变参数模板,使得可变参数的处理更加方便和灵活。可变参数模板是指模板参数个数是可变的,可以在模板定义时不确定参数的个数,需要在模板实例化时通过特定的语法来处理这些参数。

可变参数模板的语法形式为:

template <typename... Args>
void func(Args... args)
{
    // 函数体
}

其中,typename... Args表示模板参数包,可以包含任意个数的模板参数,args表示函数参数包,可以包含任意个数的函数参数。在函数体内,可以使用sizeof...(Args)来获取模板参数包中参数的个数,使用sizeof...(args)来获取函数参数包中参数的个数。

示例(可变参数模板、递归参数模板、C++17折叠表达式)

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

// ------------------------------------------------------------C++17折叠表达式

template <typename... Args>
void foldPrint(Args... args)
{
    std::cout << "The number of template arguments is: " << sizeof...(Args) << std::endl; // The number of template arguments is: 4
    std::cout << "The number of function arguments is: " << sizeof...(args) << std::endl; // The number of arguments is: 4

#if 0
    // C++17折叠表达式对可变函数参数的处理
    std::cout << "The arguments are: ";
    (std::cout << ... << args) << std::endl; // The arguments are: 12helloc
#endif
}

// ------------------------------------------------------------递归函数模板

// 基本模板函数
template <typename T>
void recursionPrint(T t)
{
    std::cout << t << std::endl;
}

// 特化版本,用于处理空参数包的情况
// template <>
// void recursionPrint<>(int t)
// {
//     std::cout << t << std::endl;
// }

// 递归模板函数(当参数还剩一个时,就会调到上面那个基本模板函数那儿)
template <typename T, typename... Args>
void recursionPrint(T t, Args... args)
{
    std::cout << t << ", "; // 不endl不会刷新缓冲区
    recursionPrint(args...);
}

// ------------------------------------------------------------C++11 可变参数模板和 C++17 折叠表达式

template <typename... Args>
void variablePrint(Args... args)
{
    int arr[] = {(std::cout << args << ", ", 0)...}; // 这段代码是使用了 C++11 中的可变参数模板和折叠表达式,可以将多个参数打印出来并存储在数组中。
    // 具体来说,代码中的 args 是一个可变参数模板,表示可以接受任意数量的参数。
    //(std::cout << args << ", ", 0) 是一个折叠表达式,表示对于每个参数,先将其输出到标准输出流 std::cout 中,然后再输出一个逗号和一个空格,并返回 0。
    // 这样,对于每个参数,都会输出到标准输出流中,并返回 0。
    // 最后,使用花括号将所有参数的输出结果存储在一个数组 arr 中,这个数组的类型是 int[],因为折叠表达式中返回的是 0,所以数组中的每个元素都是 0。
    // 需要注意的是,这段代码的输出结果中,每个参数之间都会有一个逗号和一个空格,最后一个参数后面也会有一个逗号和一个空格。
    // 如果需要去掉最后一个参数后面的逗号和空格,可以在输出数组元素时进行特判。
    std::cout << std::endl;
}

int main()
{
    // C++17折叠表达式
    std::cout << "C++17折叠表达式" << std::endl;
    foldPrint(1, 2.0, "hello", 'c');
    std::cout << std::endl;

    // 递归函数模板
    std::cout << "递归函数模板" << std::endl;
    recursionPrint(1, 2.0, "hello", 'c'); // 1, 2, hello, c
    std::cout << std::endl;

    // 可变参数模板
    std::cout << "C++11 可变参数模板和 C++17 折叠表达式" << std::endl;
    variablePrint(1, 2.0, "hello", 'c'); // 1, 2, hello, c,
    std::cout << std::endl;

    return 0;
}

运行结果:

c++ 参数包,C/C++,c++,开发语言,算法

可变参数模板的使用方式有两种,递归展开和参数包展开

递归展开

递归展开是指在函数模板内部使用递归调用来处理可变参数,直到处理完所有参数。例如,下面是一个递归展开可变参数模板的示例:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

template <typename T>
void print(T t)
{
    cout << t << endl;
}

template <typename T, typename... Args>
void print(T t, Args... args)
{
    cout << t << ", ";
    print(args...);
}

int main()
{
    print(1, 2.0, "hello"); // 输出1, 2, hello
    return 0;
}

c++ 参数包,C/C++,c++,开发语言,算法

在上面的示例中,print函数模板使用递归调用来处理可变参数,首先输出第一个参数t,然后递归调用print函数模板来处理剩余的参数args。

参数包展开(只支持C++17)

参数包展开是指使用特定的语法来展开参数包,将参数包中的参数逐个传递给函数。例如,下面是一个参数包展开可变参数模板的示例:

#include <iostream>
#include <string>
#include <cstring>
using namespace std;

#include <iostream>

using namespace std;

template <typename... Args>
void print(Args... args)
{
    cout << sizeof...(args) << endl; // 输出参数个数
    (cout << ... << args) << endl;   // 展开参数包
}

int main()
{
    print(1, 2.0, "hello"); // 输出3和12hello
    return 0;
}

c++ 参数包,C/C++,c++,开发语言,算法

在上面的示例中,print函数模板使用sizeof...(args)来获取参数个数,使用(cout << ... << args)来展开参数包,将参数包中的参数逐个传递给cout输出。

为什么template <typename... Args>模板参数中...放Args前面,void printSizeOfArgs(Args... args)中...放Args后面?

template <typename... Args>中的...放在Args前面是因为它表示一个模板参数包,用于接收任意数量的模板参数。而void printSizeOfArgs(Args... args)中的...放在Args后面是因为它表示一个函数参数包,用于接收任意数量的函数参数。

在模板参数列表中,...表示一个参数包,它可以接收任意数量的模板参数。例如,template <typename... Args>中的Args可以接收任意数量的模板参数,比如Args<int>Args<int, double>Args<char, bool, float, double>等等。

在函数参数列表中,...表示一个参数包,它可以接收任意数量的函数参数。例如,void printSizeOfArgs(Args... args)中的args可以接收任意数量的函数参数,比如printSizeOfArgs(1)printSizeOfArgs(1, 2, 3)printSizeOfArgs("hello", 'a', 3.14)等等。

因此,...放在Args前面和后面的含义是不同的,它们分别表示模板参数包和函数参数包。

模板参数和函数参数有什么区别?

模板参数和函数参数的区别主要有以下几点:

  1. 类型不同

模板参数是用于定义模板的类型、常量或模板的类型参数,它们是在编译时确定的。而函数参数是用于传递函数调用时的实际参数,它们是在运行时确定的。

  1. 作用域不同

模板参数的作用域是整个模板,可以在模板的任何地方使用。而函数参数的作用域只在函数内部有效,不能在函数外部使用。

  1. 默认值不同

模板参数可以有默认值,如果没有显式指定模板参数的值,编译器会使用默认值。而函数参数也可以有默认值,但是只能在函数声明中指定,不能在函数定义中指定。

  1. 数量不同

模板参数的数量可以是任意的,可以定义任意数量的模板参数。而函数参数的数量是固定的,必须在函数声明中指定。

  1. 实例化不同

模板参数是在模板实例化时确定的,每个模板实例化都会生成一个新的类型或函数。而函数参数是在函数调用时确定的,每次函数调用都会使用相同的函数定义,但是传递的参数可以不同。文章来源地址https://www.toymoban.com/news/detail-720067.html

到了这里,关于C++11可变参数模板(typename... Args模板参数包或class... Args)(Args... args函数参数包)(递归展开与参数包展开(只支持C++17))的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++ 11新特性之可变参数模板

    概述         随着C++ 11标准的发布,C++语言获得了许多强大的新特性,其中一项显著提升灵活性和实用性的创新便是可变参数模板。这一特性极大地扩展了模板在处理不定数量类型或值参数时的能力,为开发者提供了更为强大且灵活的泛型编程工具。 工作机制       

    2024年02月22日
    浏览(29)
  • 【C++】C++11语法 ~ 可变参数模板

    (꒪ꇴ꒪(꒪ꇴ꒪ )🐣,我是 Scort 目前状态:大三非科班啃C++中 🌍博客主页:张小姐的猫~江湖背景 快上车🚘,握好方向盘跟我有一起打天下嘞! 送给自己的一句鸡汤🤔: 🔥真正的大师永远怀着一颗学徒的心 作者水平很有限,如果发现错误,可在评论区指正,感谢🙏 🎉🎉

    2024年02月19日
    浏览(25)
  • VScode 基础篇(Python 调试)——如何输入命令行参数(args、argv、parse_args)

    VScode在编写Python时,在各种插件的加持下,十分方便。 对于调试来讲,更是实现了一键调试! 安装Python Extension 插件后,右上角的运行可以选择调试,一键开启调试 但最近在编写脚本文件时,发现一个调试的小坑,记录下。 在调试脚本的过程中,需要为脚本文件输入args,一

    2023年04月26日
    浏览(34)
  • 【C++11】移动赋值 | 新的类功能 | 可变参数模板

    C++11中,string中的operator= 包含 参数为右值的版本 C++98中 没有移动赋值和移动构造 , 只有参数为左值 的赋值重载(operator=)和拷贝构造 本来只有两次深拷贝,但是由于调用拷贝赋值时,内部又进行一次拷贝构造,所以导致最终进行三次深拷贝 这里编译器是不能优化的, 因为优

    2024年02月08日
    浏览(29)
  • 【C++杂货铺】C++11新特性——可变参数模板

    C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模板和函数模板中只能含固定数量的模板参数,可变模板参数无疑是一个巨大的改进。然而由于可变模板参数比较抽象,使用起来需要一定的技巧,所以之一块还是比较晦涩的。本

    2024年02月03日
    浏览(29)
  • C++11『右值引用 ‖ 完美转发 ‖ 新增类功能 ‖ 可变参数模板』

    ✨个人主页: 北 海 🎉所属专栏: C++修行之路 🎃操作环境: Visual Studio 2022 版本 17.6.5 自从C++98以来,C++11无疑是一个相当成功的版本更新。它引入了许多重要的语言特性和标准库增强,为C++编程带来了重大的改进和便利。C++11的发布标志着C++语言的现代化和进步,为程序员

    2024年02月05日
    浏览(35)
  • 【python基础】魔法参数*args, **kwargs的使用

    Python中传递可变参数的方式有两种,位置参数(positional argrment)和参数(keyword argument)。 本文主要讲魔法参数 *args和 **kwargs 的如何使用,如何将不定数量的参数传递给一个函数和调用一个函数。 *args 和 **kwargs 都是python中的可变参数。 *args可以用来表示任何多个无名

    2024年02月06日
    浏览(26)
  • ...args: any[] TypeScript 中的剩余参数语法

    ...args: any[] 是 TypeScript 中的剩余参数语法,也称为剩余参数(Rest Parameters)。 在函数参数列表中, ...args 表示将剩余的参数收集到一个数组中,这个数组的类型是 any[] ,即任意类型的数组。 例如: 在调用 foo 函数时,你可以传递任意数量的参数: 在函数内部, args 是一个包

    2024年02月09日
    浏览(26)
  • Go命令行参数操作:os.Args、flag包

    最近在写项目时,需要用到命令行传入的参数,正好借此机会整理一下。 运行之后的结果: 可以看到,命令行参数包括了程序路径本身,以及通常意义上的参数。 程序中os.Args的类型是 []string ,也就是字符串切片。所以可以在for循环的range中遍历,还可以用 len(os.Args) 来获取

    2024年02月08日
    浏览(33)
  • 【C++进阶】C++11(下)可变参数模板&lambda表达式&包装器

    我们紧接着上一节的讲解来进行 C++11的新特性可变参数模板能够让您创建可以接受可变参数的函数模板和类模板,相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进。然而由于可变模版参数比较抽象,使用起来需要一定的技巧

    2024年04月11日
    浏览(69)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包