c++11--变长模板

1.变长模板
1.1.变长模板定义
支持不限制数量的模板参数

// tuple是一个模板类
// 模板形参:可变数量的类型
template <typename... Elements>
class tuple{}
tuple<int, char, double> a;

// NonTypeVar是一个模板类
// 模板形参:可变数量的int类型数值
template<int... A>
class NonTypeVar{};
NonTypeVar<1, 0, 2> aa;

1.2.变长模板使用
(1).使用模板参数包

#include <iostream>
// B是一个模板类
// 模板形参:两个类型
template<typename T1, typename T2>
class B { 
};

// B<int, double>是一个特化的模板类
// 模板形参:int,double
template <>
class B<int, double> {
public:
    B() {
    	printf("B<int,double>\n");
    }
};

// Temp是一个模板类
// 模板形参:可变数量的类型
// A...代表对typename... A为代表的部分的一个引用。
template<typename... A>
class Temp:private B<A...> {
};

// 这个xy将私有继承B<int, double>
Temp<int, double> xy;
int main(){
    return 0;
}

在这里插入图片描述
(2).对可变参数模板结合模板特化展开

#include <iostream>

// tuple是一个模板类
// 模板形参:可变个数类型
template<typename... E>
class tuple{
public:
    tuple(){
        printf("normal\n");
    }
};

// tuple<Head, Tail...>是一个特化模板类
// 模板形参:可变个数类型。从第二到最后一个类型可通过Tail...来整体引用
template<typename Head, typename... Tail>
class tuple<Head, Tail...>:private tuple<Tail...>{
public:
    tuple(){printf("sizeof_%d\n", sizeof(Head));}
    Head h;
};

// tuple<>是一个特化模板类
// 模板形参:空
template<>
class tuple<>{
public:
    tuple(){
        printf("null\n");
    }
};

tuple<double,short,char,float> a;
int main(){
    return 0;
}

在这里插入图片描述
另一个等价实例

#include <iostream>
using namespace std;

template<long... num>
struct Multiply{};

template<long first, long... last>
struct Multiply<first, last...>{
    static const long val = first * Multiply<last...>::val;
};

template<>
struct Multiply<>{
    static const long val = 1;
};

int main(){
    cout << Multiply<2,3,4,5>::val << endl;
    return 0;
}

在这里插入图片描述
(3).基于变长模板的模板函数

// f是一个模板函数
// 函数形参:可变个数类型的变量
template<typename... T>
void f(T... args){
}

int main(){
	f(1, 1.0);//实例化为f(int a, double b)
	f(1);//实例化为f(int)
}

利用模板参数包,函数参数包可实现c的变长函数的一个实例

#include <iostream>
#include <stdexcept>
using namespace std;

void Printf(const char* s){
    while(*s){
        if(*s == '%' && *++s != '%'){
            throw runtime_error("invalid format string: missing arguments");
        }
        cout << *s++;
    }
}

// Printf是一个模板函数
// 函数形参:首个参数必须是const char*,第二个参数必须是某个类型,第三到最后为可变数量个类型
template<typename T, typename... Args>
void Printf(const char* s, T value, Args... args){
    while(*s){
        if(*s == '%' && *++s != '%'){
            cout << value;
            return Printf(++s, args...);
        }
        cout << *s++;
    }
    throw runtime_error("extra arguments provided to Printf");
}

int main(){
    Printf("hello %s\n", string("world"));
    return 0;
}

c的可变参数函数printf必须依赖对格式化字符串的解析,来提取每个可变参数。
借助可变参数模板,可以不依赖格式化字符串,借助模板类型推导,可变参数包来依次得到每个模板参数的类型和实参。

(4).使用参数包时允许添加修饰符

#include <iostream>
using namespace std;
template<typename... T>
void DummyWrapper(T... t){
}

template<typename T>
T pr(T t){
    cout << t;
    return t;
}

// VTPrint是一个模板函数
// 函数形参:可变数量的类型
template<typename... A>
void VTPrint(A... a){
	// 通过a...可以整体引用A... a
	// 通过pr(a)...,相当于整体引用A... a时,对其中每个元素t引用的是pr(t)
    DummyWrapper(pr(a)...);
}

int main(){
    VTPrint(1, ", ", 1.2, ", abc\n");
    cout << endl;
    return 0;
}

在这里插入图片描述
打印顺序不符合实参顺序,是由于形参求值顺序并非从左到右引起的。

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

raindayinrain

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值