模板编程-可变参数

前言

之前一直没有想法去了解可变参数,因为知道大概原理,就懒得了解细节了,今天偶然下发现了一篇写的很具参考意义的文章,就想着搬运一下。
搬运地址

https://www.cnblogs.com/qicosmos/p/4325949.html

一、可变参数定义

typename…表示有0-N个参数,可以输入0个参数也可以输入没有指定次数的参数。他大大拓展了模板的使用。

template<typename ...T1>
void fun(T1... Args){}

贴原文

可变参数模板和普通模板的语义是一样的,只是写法上稍有区别,声明可变参数模板时需要在typename或class后面带上省略号“…”。比如我们常常这样声明一个可变模版参数:template<typename…>或者template<class…>,一个典型的可变模版参数的定义是这样的:

template <class… T>
void f(T… args);
  上面的可变模版参数的定义当中,省略号的作用有两个:
1.声明一个参数包T… args,这个参数包中可以包含0到任意个模板参数;
2.在模板定义的右边,可以将参数包展开成一个一个独立的参数。

上面的参数args前面有省略号,所以它就是一个可变模版参数,我们把带省略号的参数称为“参数包”,它里面包含了0到N(N>=0)个模版参数。我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。

二、可变参数个数求取

sizeof…(Args)可以求取参数个数

#include <iostream>
template<typename ...T1>
void fun(T1... Args)
{
    std::cout << sizeof...(Args) << std::endl;
}
int main()
{
    int a = 1, b = 2;
    fun();//0
    fun(a);//1
    fun(a,b);//1
    return 0;
}

在这里插入图片描述

三、可变参数模板函数提取

1.递归处理,每次提取一个。

#include <iostream>
//既然是递归就要给出终止条件,因此当参数剩余1个时就要给出终止条件。
template<typename First>
void fun(First t)
{
    std::cout << t << std::endl;
}
//递归去提取值,每次拿出一个。
template<typename First, typename ...Rest>
void fun(First t, Rest... rest)
{
    std::cout << t << std::endl;
    //这里常用的方式std::forward<Rest>(rest)...的意思是对每一个都进行同样的处理。实际表述是(std::forward<1>(1)...std::forward<n>(n)))
    fun(rest...);
}
int main()
{
    int a = 1, b = 2;
    fun(a, b);
    return 0;
}

在这里插入图片描述

2. 逗号表达式方式去展开(很强的想法)

#include <iostream>
template<typename T>
void fun(T t)
{
    std::cout << t << std::endl;
}
template<typename... T>
void fun(T... args)
{
	//利用,会先执行前边,后执行后边,最后取后边那个值
	//(fun(args),0)...实际就是{(fun(1),0),,,(fun(n),0)}
	//调用顺序根据,原则先fun(args)调用完事后,在调用0赋值给数组。
    int arr[] = { (fun(args),0)...};
}
int main()
{
    int a = 1, b = 2;
    fun(a, b);
    return 0;
}

在这里插入图片描述

三、可变参数模板类提取

1.递归处理,每次提取一个。(特化最后的结果)

//提取传入所有类型中最后的类型
#include <iostream>
template<typename T, typename... Rest>
struct train
{
    using type = typename train<Rest...>::type;
};
template<typename T>
struct train<T>
{
    using type = T;
};
int main(void)
{
    train<int, bool, double>::type a;
    train<int, bool>::type b;
    return 0;
}

在这里插入图片描述

2. 继承方式提取可变参数

#include <iostream>
//对第一个类型重新定义。
template<bool B, typename F, typename... T>
struct MyStruct
{
    using type = F;
};
//利用特化对第二个参数类型进行重新定义
template<typename F, typename N, typename... T>
struct MyStruct<false, F, N, T...>
{
    using type = typename MyStruct<true, N, T...>::type;
};
//当参数是一个或者零个时让内部值为false
template<typename... T>
struct is_type
{
    static constexpr bool value = false;
};
//当参数是两个以上时取第二个参数为新类型,就是利用继承的方式对可变参数进行了解析
template<typename F, typename N, typename... T>
struct is_type<F, N, T...> : MyStruct<false, F, N, T...>
{
    static constexpr bool value = true;
};

int main(void)
{
    bool a = is_type<int>::value;
    bool b = is_type<int, double>::value;
    is_type<int, double>::type c;
    return 0;
}

在这里插入图片描述

总结

可变参数对于想学模板变成是必须要掌握的。只有看懂可变参数提取,才能看懂源码里的各种操作。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值