第20课 可变参数模板(1)_模板参数包和函数参数包

1.  参数包(parameter pack)

(1)模板参数包(以tuple为例):template<typename Elements>class tuple

  ①Elements标识符的左侧使用了省略号,在C++11中Elements被称为“模板参数包”,表示可以接受任意多个参数作为模板参数

  ②编译器将多个模板参数打包成“单个”的模板参数包,如tuple<int, char, double>实例化模板类时,Element就是包含int、char和double三种类型的集合。

  ③模板参数包可以是类类型非类类型的,还可以是模板类型的。非类型的模板参数包如template<int…A> class Test{};其中的A是int类型,而不是类类型。

(2)函数参数包:如template<typename…T> void f(T…args);

  ①args被称为函数参数包,表示函数可以接受多个任意类型的参数。(T被声明为模板参数包,注意与args的不同!

  ②在C++11标准中,要求函数参数包必须唯一,且是函数的最后一个参数(模板参数包没有这样的要求)

(3)关于省略号“…”

  ①当声明一个变量(或标识符)为可变参数时,省略号位于该变量的左侧。如template< typename Elements >中的Elements,以及template<typename…T> void f(T…args)中T和args都被声明为可变参数,因此省略号位于这些变量的左侧,表明它们是一个参数包。

  ②当使用参数包时,省略号位于参数名称的右侧,表示立即展开该参数,这个过程也被称为解包。如template<typename…A> class Test : public Demo<A…>{}里面的“A…”,很明显A在typename里被声明为可变模板参数,而Demo中己经是在使用而不是在定义这个变量,所以省略号位于变量A的右侧。

2. 几种常见的包扩展表达式

(1)Args&&…:包扩展解包后等价于:Arg1&&,…Argn&&。

(2)template<typename…A> class Test: private Demo<A>…{}和template<typename…A> class Test: private Demo<A…>{}的区别,当实例化Test<X,Y>后,

  ①前者等价于template<typename…A> class Test : private Demo<X>, private Demo<Y>的多重继承形式。

  ②后者相当于template<typename…A> class Test : private Demo<X, Y>,即派生于多参数的模板类。

(3)设args被声明为一个函数参数包,则

  ①printArgs(args…):相当于printArgs(args1,args2,…,argsN)。

  ②printArgs(args)…:相当于printArgs(args1),…, printArgs(argsN)

  ③(printArgs(args),0)…:这是一个逗号表达式。相当于(printArgs(args1),0),…(printArgs(argsN),0)

【小结】包扩展表达式“exp…”相当于将省略号左侧的参数包exp(可能是个变量或表达式)视为一个整体来进行扩展

【实例分析】参数包和包扩展

//example 1:
template<typename T, typename... Args>  //声明Args为模板参数包,省略号位地参数名称的左侧
void Print(T t, Args... args) //声明args为函数参数包,省略号位于参数名称的左侧
{
    cout << t;
    Print(args...); //使用args参数后(注意省略号在右侧),解包后为Print(arg1,arg2,...argN);
}

//example 2:
template<class T>
void printarg(T t){}

template<class ...Args>   //声明Args为模板参数包,
void expand(Args... args) //声明args为函数参数包
{
    int arr[] = {(printarg(args),0)...}; //(printarg(args),0)为逗号表达式,后面加省略号相当
                                         //于:(printarg(args1),0),...(printarg(argsN),0)
}

//example 3:
template<typename ... T> void Wraper(T... t){} //包装器

template<typename T> T printA(T t) //打印参数
{
    cout << t;
    return t;
}

template<typename... Args>
void printArgs(Args... args)
{
    Wraper(printA(args)...); //包扩展解包为:Wrap(printA(arg1),...,printA(argN));
                             //注意printA的返回值为参数本身的类型。
}

//example 4:
template <typename First, typename... Rest> //声明Rest模板参数包
struct Sum<First, Rest...>  //Rest前面己经声明好,这里是在使用Rest(省略后在右侧)
{                           //相当于Sum<First, Rest1,...,RestN>
    enum{value = Sum<First>::value + Sum<Rest...>::value;}; //使用Rest(省略后在右侧)
}

//example 5:
template<typename ...Types>  //Types为模板参数包
void func1(std::vector<Types...> v1);  //注意,v1不是函数参数包

template<typename ...Types>  //Types为模板参数包
void func1(std::vector<Types>... v2);  //注意,v2是函数参数包(...应位于“top-level”)

//example 6:
template <typename... A>
class Test : private B<A>...{};  

class Test<X, Y> test;  //<==>class Test<X, Y> : private B<X>, private B<Y>{}

template <typename... A>
class Test : private B<A>...{};

class Test<X, Y> test //<==>class Test<X, Y> : private B<X, Y>{}
时间: 2024-10-05 10:02:11

第20课 可变参数模板(1)_模板参数包和函数参数包的相关文章

第21课 可变参数模板(2)_展开参数包

1. 可变参数模板函数 (1)递归函数方式展开参数包 ①一般需要提供前向声明.一个参数包的展开函数和一个递归终止函数. ②前向声明有时可省略,递归终止函数可以是0个或n个参数 (2)逗号表达式和初始化列表方式展开参数包 ①逗号表达式按顺序执行,返回最后一个表达式的值. ②initilizer_list可接受任意多个不同类型的参数. ③借助逗号表达式来展开包,并将返回的结果用于初始化initilizer_list. [编程实验]展开可变参数模板函数的参数包 #include <iostream>

第23课 可变参数模板(4)_Optional和Lazy类的实现

1. optional类的实现 (1)optional的功能 ①optional<T>的内部存储空间可能存储了T类型的值,也可能没有.只有当optional被T初始化之后,这个optional才是有效的.否则是无效的.它实现了未初始化的概念. ②optional可以用于解决函数返回无效值的问题.当函数返回一个未初始化的Optional对象时,表明函数正确执行了,只是结果不是有用的值. ③举例:optional<int> op; //未被初始化. optional<int>

C++_二维数组作为函数参数的使用方法

二维数组作为函数参数的使用方法 /*01)恒等式:ar2[r][c] == *(*(ar2+r)+c)03) ar2+r指向编号为r的元素,该元素由c个int型(或其他类型)数组成,编号从0开始02)int a[100][4]; ....   int total = sum(a,100); //在主函数中调用sum()函数,使用二维数组中的全部的数据   int total = sum(a,10); //在主函数中调用sum()函数,使用二维数组中的前十行数据   int total = sum

c++11可变参数模板的使用1

1.概述 C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数.相比C++98/03,类模版和函数模版中只能含固定数量的模版参数,可变模版参数无疑是一个巨大的改进.然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以它也是C++11中最难理解和掌握的特性之一. 虽然掌握可变模版参数有一定难度,但是它却是C++11中最有意思的一个特性,本文希望带领读者由浅入深的认识和掌握这一

c++11 可变参数模板函数

c++11 可变参数模板函数 #define _CRT_SECURE_NO_WARNINGS #include <iostream> #include <string> #include <vector> #include <map> // 在C++11之前,类模板和函数模板只能含有固定数量的模板参数.C++11增强了模板功能,允许模板定义中包含0到任意个模板参数,这就是可变参数模板. // 可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变

C++ 11 可变参数模板和 boost::any 实现可变参数函数

1 class SqlHelper 2 { 3 public: 4 template <typename... Params> 5 static bool preparedExecute(sql::PreparedStatement* pstmt, Params... parameters) 6 { 7 return doPreparedExecute(pstmt, 1, parameters...); 8 } 9 10 private: 11 template <typename...

可变参数模板用法

//可变参数模板 //可变参数模板,可以创建可接受可变数量参数的模板函数和模板类 //本程序通过模板函数来实例一下可变参数模板的基本用法 #include<iostream> using namespace std; void one(){}//当最后一个参数传完后,需要一个无参的重载版本 template <typename T>//当只剩最后一个参数时,编译器优先选择此模板,这样最后一个输出后面就没有逗号了 void one(T v) { cout << v <

ThinkPHP项目CMS内容管理系统开发视频教程【20课】(3.02GB)

ThinkPHP背景介绍:     ThinkPHP是一个免费开源的,快速.简单的面向对象的轻量级PHP开发框架,遵循Apache2开源协议发布,是为了敏捷WEB应用开发和简化企业级应用开发而诞生的.拥有众多的优秀功能和特性,经历了三年多发展的同时,在社区团队的积极参与下,在易用性.扩展性和性能方面不断优化和改进,众多的典型案例确保可以稳定用于商业以及门户级的开发.教程目录:第1讲ThinkPHP搭建CMS项目设计01.rmvb 123.2MB第2讲ThinkPHP搭建CMS项目设计02.rmv

C++反射机制:可变参数模板实现C++反射

1. 概要   本文描述一个通过C++可变参数模板实现C++反射机制的方法.该方法非常实用,在Nebula高性能网络框架中大量应用,实现了非常强大的动态加载动态创建功能.Nebula框架在coding.net的仓库地址.   C++11的新特性--可变模版参数(variadic templates)是C++11新增的最强大的特性之一,它对参数进行了高度泛化,它能表示0到任意个数.任意类型的参数.关于可变参数模板的原理和应用不是本文重点,不过通过本文中的例子也可充分了解可变参数模板是如何应用的.