跟我学c++中级篇——变参模板的应用
创始人
2024-03-24 17:32:50

一、说明

很多技术学会了是学会了,但是转眼就会忘记。这也是很多技术被束之高阁的主要原因,没有应用场景。当然,有了应用场景不用,那是另外一回事。那么,一个技术的产生一定是从实际的应用场景中来,但是传播的过程中,可能反而让很多人忘记了这个应用场景是什么。所以今天就聊聊这个变参模板到底怎么用,给出一些在实际场景中模拟的例子,让人一看就明白的那类。这样,有了同样类似的场景,就可以考虑把这个变参模板应用上去。
在前面的分析中可以看到,一个变参模板类一般分为三部分,第一部分是模板类的前置声明用来声明一个可变参数模板类;然后是一般的展开形式,也就是通过偏特化来实现部分可展开的模板类,最后就是反复提到的终止定义模板类来保证递归等的结束判断,这里一般是一个特化的类或者是一个全实例化的类。
在实际的应用中,就可以把这块专门编写模板封装起来,供外部调用。

二、应用

下面举出三个场景来应用变参模板:

1、实现工厂类
如果在实际场景中,需要一个工厂模式(可不要说从来没遇到过用工厂模式),这个工厂模式有不确定多个参数和类型需要传递,怎么办?传统的方式可以写很多个重载函数,或者写一个最长,然后每个都有默认参数,根据实际传入的参数来决定到底采用哪种方式来创建实例。但是这样做显得代码臃肿且不易维护和扩展。当然,也可以抽象一个类(接口),子类来继承,通过动态创建不同的类来实现,但这就需要维护者去编写这个继承类,这或多或少也会让开发者感到有些不好理解,特别是如果这个父类被封装到一个DLL库中,看不到实际的代码时,更是如此。那么变参模板就很容易实现:
先看一下如果不使用变参模板:

template
T* Instance()
{return new T();
}template
T* Instance(T0 arg0)
{return new T(arg0);
}template
T* Instance(T0 arg0, T1 arg1)
{return new T(arg0, arg1);
}
//..............
//当然后面还可以写更多个参数类型的
#include class Example0
{
public:Example0(int) {std::cout << "class instance example0!" << std::endl;}
};class Example1
{
public:Example1(int, double) {std::cout << "class instance example1!" << std::endl;}
};
int main()
{Example0* pa = Instance(3);Example1* pb = Instance(3,2.0);
}

再看使用变参模板:

#include 
#include 
#include class Example0
{
public:Example0(int) {std::cout << "class instance example0!" << std::endl;}
};class Example1
{
public:Example1(int, double) {std::cout << "class instance example1!" << std::endl;}
};
struct Example2
{Example2(int, double,std::string) {std::cout << "struct instance example3!" << std::endl;}
};
template
std::shared_ptr Instance(Args&&... args)
{return std::make_shared(std::forward(args)...);//return std::shared_ptr(new T(std::forward(args)...));
}
void TestInstance()
{std::shared_ptr p0 = Instance(1);std::shared_ptr p1 = Instance(1, 2.0);std::shared_ptr p2 = Instance(1, 2,"Test");
}
int main()
{TestInstance();return 0;
}

这样写比上面简洁多了,这就是标准进步的结果。

2、实现类似代理委托
如果有c#或者Java开发经验的就会知道,其中的委托delegate非常好用。各种函数都可以轻易的转发调度。那么,在c++中用变参模板就可以近似实现类似的功能,而且比之更灵活,看下面的例子:

template 
class  CppDelegate
{
public:CppDelegate(T* t, R(T::* func)(Args...)) :t_(t), func_(func) {}R operator()(Args&&... args){return (t_->*func_)(std::forward(args) ...);}private:T * t_;R(T::* func_)(Args...);//万能函数
};template 
CppDelegate CreateDelegate(T* t, R(T::* f)(Args...))
{return CppDelegate(t, f);
}class DgEx
{
public:void MyFunc0(int d) { std::cout << d << std::endl; }void MyFunc1(int d, std::string s) { std::cout << s << d << std::endl; }int MyFunc2(std::string s,int d) { std::cout << s << std::endl; return d; }
};void TestDelegate()
{DgEx de;auto d0 = CreateDelegate(&de, &DgEx::MyFunc0);d0(16);auto d1 = CreateDelegate(&de, &DgEx::MyFunc1);d1(6, "display:");auto d2 = CreateDelegate(&de, &DgEx::MyFunc2);int r = d2("this is test!",3);std::cout << "return value is:" << r << std::endl;
}
void TestDelegate();int main()
{TestDelegate();return 0;
}

这里面有一个万能函数,不知道还记不记得“C++变参函数实现三步曲之三C++11变参模板模式”文中就提到了这种方式。不过这个还是比较功能单一,大家可以在这个基础上进行扩展。

3、std::bind的变参绑定
这个在前面提到的文章中也有过描述,看一个例子:

#include 
#include 
#include class MyBind
{
public:templatevoid Call(T&... args){{func_ = std::bind(&MyBind::Test, this, args...);std::cout << "test bind args..." << std::endl;func_();}}templatevoid Test(T&... args){std::cout << "call Test " << std::endl;}std::function func_;};int  TestMyBind()
{int a = 6;double b = 3.9;std::string c{ "test bind" };MyBind myBind;myBind.Call(a, b, c);return 0;
}

都是需要认真看才能搞清楚,所以看这些例子,还是要仔细静下心来,弄明白了,就真的掌握了。不要看看会,就觉得会了,自己写一个试试,可能会有意外的惊喜。
这三个例子,都是比较好的应用场景,在这些简单的例子的入门引导下,就可以不断的在实际的应用中完善修改,最终形成一个符合自己工程应用的模块,最合适的才是最好的。

三、总结

学以致用,这句话说起来容易,可做起来真难啊。如果不能深刻的理解一门技术,就无法自如的应用他,而只能照猫画虎的外向型模仿。不过,这种外向型模仿却又是深刻理解的前提和基础。学习本身就是一个由表及里,由外到内的过程。越是学习应用的多,对一门技术的理解就会越发的深刻。而反过来,应用这门技术就会越发的灵活自如。
计算机技术就是如此,多读书,勤实践,不断的从理论到实践并不断的反馈自己对理论的理解,如此往复,其期可待。

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
demo什么意思 demo版本... 618快到了,各位的小金库大概也在准备开闸放水了吧。没有小金库的,也该向老婆撒娇卖萌服个软了,一切只...