Variadic Templates

本文深入探讨了C++中的可变参数模板,包括如何定义和使用可变参函数模板,以及参数包的展开。同时,讲解了可变参类模板的泛化和特化,并展示了如何通过递归方式展开参数包。内容涵盖函数模板的递归终止条件和类模板的构造函数执行顺序。

一、可变参函数模板

/*********************可变参数函数模板**********************/
template<typename... T> //T:一包类型 ,args: 一包形参
void myfunc(T... args)
{
    cout << "可变参数 函数 模板" << endl;
    cout << sizeof...(args) << endl;
    cout << sizeof...(T) << endl;
}
  • 注意这三个点(…)出现的位置。在具体的函数形参中,出现在了类型名的后面(Eg:T…)。但如果这个类型后面有引用,则出现在引用的后面(Eg: T&…)。具体示例如下。
template<typename T,typename... U>
void myfunc1(const T& firstarg, const U&... othetarg)
{
    cout << "含有一个非变参的类型typename T,typename... U" << endl;
    //cout << sizeof...(firstarg) << endl;  //sizeof...只能用在一包类型或一包形参上
    cout << sizeof...(othetarg) << endl;
}
函数包的展开

函数包的展开会利用与函数模板一样的同名函数,来作为终止条件,此函数需要注意的是参数为空。
递归函数的方式展开函数包,对于函数模板也有一般的形式要求。

  1. 带一个单独的参数;
  2. 后面跟一个“一包参数”;
/*********************参数包的展开(递归函数的方式展开)**********************/
//先写一个函数模板的同名函数,作为展开的终止函数,此函数 的形参要为0
void display_args()
{
    cout << "执行了终止函数" << endl;
}
template<typename T,typename... U>
void display_args(const T& firstarg, const U&... otherargs)
{
    cout << firstarg << endl;
    display_args(otherargs...); //注意传进来的是一包形参,这里的...不能省略
}
  • 因为参数是一个个被剥离,到最后一次的时候参数为空,而函数模板的参数至少为一个,当参数为空的时候会调用与函数模板同名的函数,来作为递归的终止条件。

二、可变参类模板

在类的模板中先有泛化后有特化。可变参类模板的用途一般定位为中高级应用。

/*********************可变参数类模板**********************/
//泛化版本的模板(现有泛化才有特化)
template<typename... Args>
class MyClass
{
public:
    MyClass() 
    {
        printf("MyClass::MyClass()泛化版本执行了,this = %p\r\n", this);
    }
};
///*****************************当增加了一个特殊的特化类模板会被先执行(当和泛化类模板共存时)******************************************************/
//template<>
//class MyClass<>
//{
//public:
//    MyClass()
//    {
//        printf("MyClass::MyClass()特殊的特化版本执行了,this = %p\r\n", this);
//    }
//};
///***********************************************************************************/

//可变参类模板
template<typename First,typename...Others> 
class MyClass<First,Others...>: private MyClass<Others...>      //先执行父类的构造函数,后执行子类的构造函数
{
public:
    MyClass() :m_i(0)
    {
        printf("MyClass::MyClass()偏特化版本执行了,this = %p, sizeof...(Others) = %d\r\n", this, sizeof...(Others));
    }
    //增加一个有参数的构造函数
    MyClass(First parf, Others... paro):m_i(parf),MyClass<Others...>(paro...)   //注意此处第二个参数的写法
    {
        cout << "-------------------begin--------------------" << endl;
        printf("MyClass::MyClass(parf,...paro)执行了,this = %p\n", this);
        cout << "m_i = " << m_i << endl;
        cout << "--------------------end---------------------" << endl;
    }
    First m_i;
};

这是通过递归的方式展开参数包。类似于函数模板的展开,在递归继承的时候,参数为空就会停止类模板的继承,进而实例化一个泛化版本的类。具体的层次关系如下。

可变参类模板递归继承方式层次关系
在类的实例化中先执行的是父类的构造函数。

35 0 C:\Program Files (x86)\Dev-Cpp\MinGW64\lib\gcc\x86_64-w64-mingw32\4.9.2\include\c++\array In file included from C:/Program Files (x86)/Dev-Cpp/MinGW64/lib/gcc/x86_64-w64-mingw32/4.9.2/include/c++/array 2 D:\范铭博编程文件\特殊\牛逼的东西.cpp from D:\范铭博编程文件\特殊\牛逼的东西.cpp 32 2 C:\Program Files (x86)\Dev-Cpp\MinGW64\lib\gcc\x86_64-w64-mingw32\4.9.2\include\c++\bits\c++0x_warning.h [Error] #error This file requires compiler and library support for the ISO C++ 2011 standard. This support is currently experimental, and must be enabled with the -std=c++11 or -std=gnu++11 compiler options. 8 1 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'constexpr' does not name a type 8 1 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] C++11 'constexpr' only available with -std=c++11 or -std=gnu++11 D:\范铭博编程文件\特殊\牛逼的东西.cpp In function 'int main()': 26 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'constexpr' was not declared in this scope 30 14 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'function' in namespace 'std' does not name a template type 31 30 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expected ')' before '<' token D:\范铭博编程文件\特殊\牛逼的东西.cpp In destructor 'main()::Printer::~Printer()': 32 29 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'action' was not declared in this scope D:\范铭博编程文件\特殊\牛逼的东西.cpp In lambda function: 39 35 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Warning] extended initializer lists only available with -std=c++11 or -std=gnu++11 D:\范铭博编程文件\特殊\牛逼的东西.cpp In function 'int main()': 42 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Warning] lambda expressions only available with -std=c++11 or -std=gnu++11 42 6 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] no matching function for call to 'main()::Printer::Printer(main()::<lambda()>)' 42 6 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] candidates are: 29 12 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] main()::Printer::Printer() 29 12 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] candidate expects 0 arguments, 1 provided 29 12 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] main()::Printer::Printer(const main()::Printer&) 29 12 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] no known conversion for argument 1 from 'main()::<lambda()>' to 'const main()::Printer&' 45 7 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'struct main()::Printer' has no member named 'action' 48 16 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Warning] variadic templates only available with -std=c++11 or -std=gnu++11 48 16 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expansion pattern 'int' contains no argument packs D:\范铭博编程文件\特殊\牛逼的东西.cpp In lambda function: 49 9 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'array' is not a member of 'std' 50 19 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'arr' was not declared in this scope 52 19 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] 'x' does not name a type 53 9 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expected ';' before 'std' 54 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expected primary-expression before '}' token 54 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expected ')' before '}' token 54 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] expected primary-expression before '}' token D:\范铭博编程文件\特殊\牛逼的东西.cpp In function 'int main()': 54 5 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Warning] lambda expressions only available with -std=c++11 or -std=gnu++11 54 20 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Error] no match for call to '(main()::<lambda()>) (int, int, int, int, int)' 48 6 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] candidates are: 54 20 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] void (*)() <conversion> 54 20 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] candidate expects 1 argument, 6 provided 48 17 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] main()::<lambda()> 48 17 D:\范铭博编程文件\特殊\牛逼的东西.cpp [Note] candidate expects 0 arguments, 5 provided
10-05
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值