jjzjj

还在因为写项目函数太多而烦恼?C++模板一文带你解决难题

热爱编程的小K 2023-09-08 原文

📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的
📖作者主页:热爱编程的小K
📖专栏链接:c++

🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​
💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾

💯文章目录


💝一、什么是模板

模板是一种忽略数据的一种泛型编程。把数据当做未知量,当使用的时候传入类型的一种编程方式

语法

template <class T>//告诉编译器,接下来要用到一个未知类型是T类型
template <typename T>//等效class
template <class T1,class T2,class T3> //三个未知类型

#include<iostream>
#include<string>
using namespace std;
#if 0
int Max(int a, int b) 
{
	return a > b ? a : b;
}
float Max(float a, float b) 
{
	return a > b ? a : b;
}
double Max(double a, double b)
{
	return a > b ? a : b;
}
#endif
template <class T1> T1 Max(T1 a,T1 b)
{
	return a > b ? a : b;
}
int main() 
{
	cout << Max<int>(9, 10);
	return 0;
}

💖二、C++函数模板

  • 函数模板调用
    • 函数模板隐式调用
    • 显示调用:函数名<未知类型>(函数参数)
  • 函数模板本质就是函数传参
    • 函数模板也是可以缺省
  • 函数模板中存在变量
    • 这种函数模板必须显示调用
    • 变量传参只能传入常量
  • 当函数模板和普通函数相遇
    • 优先调用类型一致的普通函数
    • 显示调用一定调用模板
  • 函数模板重载
    • 优先调用传参数目少的函数模板
#include<iostream>
#include<string>
using namespace std;
template <class T1> T1 Max(T1 a, T1 b) 
{
	return a > b ? a : b;
}
template <class _T1, class _T2, class _T3> void print(_T1 a, _T2 b, _T3 c) 
{
	cout << a << "\t" << b << "\t" << c << endl;
}
template <class _T1 = int, class _T2 = string, class _T3 = double> void printData(_T1 a, _T2 b, _T3 c)
{
	cout << a << endl << b << endl << c << endl;
}
template <class _T1,int size> _T1* createNew()
{
	_T1* createNew = new _T1[size];
	return createNew;
}
template <class _T1, int size=5> _T1* createParry()
{
	_T1* createNew = new _T1[size];
	return createNew;
}
template <class _Ty, int size = 4> void printArray2(_Ty array[])
{
	for (int i = 0; i < size; i++)
	{
		cout << array[i] << "\t";
	}
	cout << endl;
}
void Func1(int a, double b, string c) 
{
	cout << "普通函数" << endl;
}
template <class _T1, class _T2, class _T3> void Func1(_T1 a,_T2 b,_T3 c) { cout << "三个" << endl; }
template <class _T1, class _T2> void Func1(_T1 a, _T2 b, _T2 c) { cout << "两个" << endl; }
template <class _T1> void Func1(_T1 a,_T1 b,_T1 c) { cout << "一个" << endl; }

void test1() 
{
	//函数模板存在变量,必须显示调用
	int* parry = createNew<int, 5>();
	//变量缺省时候可以隐式调用
	double* king = createParry<double>();
	int p[4] = { 1,2,3,4 };
	printArray2(p);
}
void test2()
{
	//函数模板重载,普通函数
	Func1<int, double, string>(1,1.11,string("king"));
	Func1(1, 1.11,string("king"));
	Func1(1, string("asdd"),string("kkk"));
	Func1(1, 1, 1);
}
int main()
{
	//隐式调用
	cout << Max(1, 2) << endl;
	cout << Max(1.1, 1.2) << endl;
	cout << Max(string("abc"), string("abd")) << endl;
	print(123, string("king"), 1.55);

	//显示调用
	cout << Max<int>(1, 2) << endl;
	cout << Max<string>(string("abc"), string("abd")) << endl;
	print<string, int, double>("asdas", 123, 123.213);

	//函数模板的缺省
	printData(1, "dad", 1.11);
	printData<double, int, string>(1.11, 1, "dasdf");

	test1();
	test2();
	return 0;
}

💓三、函数模板操作自定义类型

操作自定义类型的关键点就是重载

#include<iostream>
#include<string>
using namespace std;
template <class _T1> void printpArry(_T1 arry[],int arryNums)
{
	for (int i = 0; i < arryNums; i++)
	{
		cout << arry[i] << endl;
	}
	cout << endl;
}
template <class _T1> void Sort(_T1 arry[], int arryNums) 
{
	for (int i = 0; i < arryNums; i++)
	{
		for (int j = 0; j < arryNums - i - 1; j++) 
		{
			if (arry[j] > arry[j + 1]) 
			{
				_T1 temp = arry[j];
				arry[j] = arry[j + 1];
				arry[j + 1] = temp;
			}
		}
	}
}
class MM 
{
public:
	MM(string name="", int age=0):name(name),age(age){}
	friend ostream& operator<<(ostream& out,const MM& object)
	{
		out << object.age << "\t" << object.name << endl;
		return out;
	}
	bool operator>(const MM& object) 
	{
		return this->name > object.name;
	}
	string Getname() const { return this->name; }
	int Getage() const { return this->age; }
protected:
	string name;
	int age;
};
template <class _T1> void Sort2(_T1 arry[], int arryNums,bool(*compare)(const _T1& one,const _T1& two))
{
	for (int i = 0; i < arryNums; i++)
	{
		for (int j = 0; j < arryNums - i - 1; j++)
		{
			if (compare(arry[j] , arry[j + 1]))
			{
				_T1 temp = arry[j];
				arry[j] = arry[j + 1];
				arry[j + 1] = temp;
			}
		}
	}
}
bool compareByname(const MM& one, const MM& two)
{
	return one.Getname() > two.Getname();
}
bool compareByage(const MM& one, const MM& two)
{
	return one.Getage() > two.Getage();
}
int main() 
{
	int parry[5] = { 1,20,6,7,90 };
	Sort(parry, 5);
	printpArry(parry, 5);
	MM mm[3];
	mm[0] = { "e",123 };
	mm[1] = { "b",241 };
	mm[2] = { "d",345 };
	Sort(mm, 3);
	printpArry(mm, 3);
	Sort2(mm, 3,compareByage);
	printpArry(mm, 3);
	return 0;
}

💞四、C++类模板

  • template修饰的类就是类模板
  • 模板类必须显示实例化,简单来说必须要传参
  • 模板类不是一个真正的类型
    • 声明和实现必须写在一起,所谓一起就是同一个文件中
    • 所有用到类型的地方必须要用类名<未知类型>的用法
  • 类模板特化
    • 局部特化:特殊化处理,例如两个未知变成一个未知类型
    • 完全特化:具体化类型
#include<iostream>
#include<string>
using namespace std;
template <class _T1,class _T2> class Data
{
public:
	void print();
	static int count;
};
template <class _T1, class _T2> int Data<_T1, _T2>::count = 0;
template <class _T1, class _T2> void Data<_T1, _T2>::print() 
{
	cout << "类中模板函数" << endl;
}
//类模板的继承
template <class _T1, class _T2> class Son : public Data<_T1, _T2> 
{
public:
protected:
};
struct MMinfor 
{
	string name;
	int age;
};
ostream& operator<<(ostream& out, const MMinfor& object) 
{
	out << object.age << "\t" << object.name << endl;
	return out;
}
struct MMscore 
{
	int math;
	int english;
	int chinese;
};
ostream& operator<<(ostream& out, const MMscore& object)
{
	out << object.math << "\t" << object.english << "\t" << object.chinese << endl;
	return out;
}
template <class _T1, class _T2> class MM 
{
public:
	MM(_T1 one,_T2 two):one(one),two(two){}
	void print() { cout << one << "\t" << two << endl; }
protected:
	_T1 one;
	_T2 two;
};
void test1()
{
	MM < string, int > mm("king", 19);
	mm.print();
	MM<int, int> complaxe(1, 1);
	complaxe.print();
	//MMinfor info{string("zhang"), 18};
	//MMscore score{ 13,14,123 };
	//MM<MMinfor, MMscore> king(info, score);
	MM<MMinfor, MMscore> king({ "zhang",18 }, { 31,312,453 });
	king.print();
}
//类模板特化
template <class _T1, class _T2, class _T3> class A
{
public:
	A(_T1 one,_T2 two,_T3 three):one(one),two(two),three(three)
	{
		cout << "三个类型" << endl;
	}
protected:
	_T1 one;
	_T2 two;
	_T3 three;
};
//局部特化
template <class _T1> class A<_T1,_T1,_T1>
{
public:
	A(_T1 one, _T1 two, _T1 three) :one(one), two(two), three(three)
	{
		cout << "局部特化" << endl;
	}
protected:
	_T1 one;
	_T1 two;
	_T1 three;
};
//完全特化
template <> class A<int,int,int>
{
public:
	A(int one, int two, int three) :one(one), two(two), three(three)
	{
		cout << "完全特化" << endl;
	}
protected:
	int one;
	int two;
	int three;
};
void Test() 
{
	A<int, int, int> a(1, 2, 3);
	A<int, string, double> b(1, "as", 1.22);
	A<int, int, double> c(1, 2, 1.22);//三个类型
	A<string, string, string> d("qew", "fasd", "fads");
}
int main()
{
	Data<int, string> data;
	Data<string, int>* object = new Data<string, int>;
	data.print();
	object->print();
	//两个不同类型中的count,不会因为一个类型中值的改变而另一个类型中的值改变
	cout << Data<int, string>::count << endl;
	cout << Data<string, string>::count << endl;
	test1();
	Test();
	return 0;
}

💕五、稍微复杂一点的类模板

稍微复杂一点的模板就是模板类与模板类的嵌套,本质不难,大家学会剥洋葱,学会用别名替换即可

#include<iostream>
#include<string>
using namespace std;
template <class _T1, class _T2> class MM 
{
public:
	MM(_T1 one, _T2 two) :one(one), two(two) {}
	void print() { cout << one << "\t" << two << endl; }
	template <class _T1, class _T2> friend ostream& operator<<(ostream& out,const MM<_T1, _T2>& object);
protected:
	_T1 one;
	_T2 two;
};
template <class _T1, class _T2> ostream& operator<<(ostream& out,const MM<_T1, _T2>& object)
{
	out << object.one << "\t" << object.two << endl;
	return out;
}
template <class _T1, class _T2> class Data 
{
public:
	Data(_T1 one,_T2 two):one(one),two(two){}
	void print() { cout << one << "\t" << two << endl; }
	template <class _T1, class _T2>friend ostream& operator<<(ostream& out, const Data<_T1, _T2>& object);
protected:
	_T1 one;
	_T2 two;
};
template <class _T1, class _T2> ostream& operator<<(ostream& out, const Data<_T1, _T2>& object)
{
	out << object.one << "\t" << object.two << endl;
	return out;
}
int main() 
{
	MM<int, string> info(19, "king");
	MM<int, int> score(99, 88);
	Data< MM<int, string>, MM<int, int>> king(info, score);
	king.print();
	using kk = Data< MM<int, string>, MM<int, int>>;
	using kkk = MM<int, string>;
	Data<kk, kkk> data(king, info);
	data.print();

	return 0;
}

有关还在因为写项目函数太多而烦恼?C++模板一文带你解决难题的更多相关文章

  1. ruby - 通过 erb 模板输出 ruby​​ 数组 - 2

    我正在使用puppet为ruby​​程序提供一组常量。我需要提供一组主机名,我的程序将对其进行迭代。在我之前使用的bash脚本中,我只是将它作为一个puppet变量hosts=>"host1,host2"我将其提供给bash脚本作为HOSTS=显然这对ruby​​不太适用——我需要它的格式hosts=["host1","host2"]自从phosts和putsmy_array.inspect提供输出["host1","host2"]我希望使用其中之一。不幸的是,我终其一生都无法弄清楚如何让它发挥作用。我尝试了以下各项:我发现某处他们指出我需要在函数调用前放置“function_”……这

  2. ruby - 在没有 sass 引擎的情况下使用 sass 颜色函数 - 2

    我想在一个没有Sass引擎的类中使用Sass颜色函数。我已经在项目中使用了sassgem,所以我认为搭载会像以下一样简单:classRectangleincludeSass::Script::FunctionsdefcolorSass::Script::Color.new([0x82,0x39,0x06])enddefrender#hamlengineexecutedwithcontextofself#sothatwithintemlateicouldcall#%stop{offset:'0%',stop:{color:lighten(color)}}endend更新:参见上面的#re

  3. ruby-on-rails - 在 ruby​​ 中使用 gsub 函数替换单词 - 2

    我正在尝试用ruby​​中的gsub函数替换字符串中的某些单词,但有时效果很好,在某些情况下会出现此错误?这种格式有什么问题吗NoMethodError(undefinedmethod`gsub!'fornil:NilClass):模型.rbclassTest"replacethisID1",WAY=>"replacethisID2andID3",DELTA=>"replacethisID4"}end另一个模型.rbclassCheck 最佳答案 啊,我找到了!gsub!是一个非常奇怪的方法。首先,它替换了字符串,所以它实际上修改了

  4. ruby - 在 Ruby 中有条件地定义函数 - 2

    我有一些代码在几个不同的位置之一运行:作为具有调试输出的命令行工具,作为不接受任何输出的更大程序的一部分,以及在Rails环境中。有时我需要根据代码的位置对代码进行细微的更改,我意识到以下样式似乎可行:print"Testingnestedfunctionsdefined\n"CLI=trueifCLIdeftest_printprint"CommandLineVersion\n"endelsedeftest_printprint"ReleaseVersion\n"endendtest_print()这导致:TestingnestedfunctionsdefinedCommandLin

  5. 屏幕录制为什么没声音?检查这2项,轻松解决 - 2

    相信很多人在录制视频的时候都会遇到各种各样的问题,比如录制的视频没有声音。屏幕录制为什么没声音?今天小编就和大家分享一下如何录制音画同步视频的具体操作方法。如果你有录制的视频没有声音,你可以试试这个方法。 一、检查是否打开电脑系统声音相信很多小伙伴在录制视频后会发现录制的视频没有声音,屏幕录制为什么没声音?如果当时没有打开音频录制,则录制好的视频是没有声音的。因此,建议在录制前进行检查。屏幕上没有声音,很可能是因为你的电脑系统的声音被禁止了。您只需打开电脑系统的声音,即可录制音频和图画同步视频。操作方法:步骤1:点击电脑屏幕右下侧的“小喇叭”图案,在上方的选项中,选择“声音”。 步骤2:在“声

  6. 【高数】用拉格朗日中值定理解决极限问题 - 2

    首先回顾一下拉格朗日定理的内容:函数f(x)是在闭区间[a,b]上连续、开区间(a,b)上可导的函数,那么至少存在一个,使得:通过这个表达式我们可以知道,f(x)是函数的主体,a和b可以看作是主体函数f(x)中所取的两个值。那么可以有,  也就意味着我们可以用来替换 这种替换可以用在求某些多项式差的极限中。方法: 外层函数f(x)是一致的,并且h(x)和g(x)是等价无穷小。此时,利用拉格朗日定理,将原式替换为 ,再进行求解,往往会省去复合函数求极限的很多麻烦。使用要注意:1.要先找到主体函数f(x),即外层函数必须相同。2.f(x)找到后,复合部分是等价无穷小。3.要满足作差的形式。如果是加

  7. ruby - 在 Ruby 中按名称传递函数 - 2

    如何在Ruby中按名称传递函数?(我使用Ruby才几个小时,所以我还在想办法。)nums=[1,2,3,4]#Thisworks,butismoreverbosethanI'dlikenums.eachdo|i|putsiend#InJS,Icouldjustdosomethinglike:#nums.forEach(console.log)#InF#,itwouldbesomethinglike:#List.iternums(printf"%A")#InRuby,IwishIcoulddosomethinglike:nums.eachputs在Ruby中能不能做到类似的简洁?我可以只

  8. ruby-on-rails - Mandrill API 模板 - 2

    我正在使用Mandrill的RubyAPIGem并使用以下简单的测试模板:testastic按照Heroku指南中的示例,我有以下Ruby代码:require'mandrill'm=Mandrill::API.newrendered=m.templates.render'test-template',[{:header=>'someheadertext',:main_section=>'Themaincontentblock',:footer=>'asdf'}]mail(:to=>"JaysonLane",:subject=>"TestEmail")do|format|format.h

  9. C51单片机——实现用独立按键控制LED亮灭(调用函数篇) - 2

    说在前面这部分我本来是合为一篇来写的,因为目的是一样的,都是通过独立按键来控制LED闪灭本质上是起到开关的作用,即调用函数和中断函数。但是写一篇太累了,我还是决定分为两篇写,这篇是调用函数篇。在本篇中你主要看到这些东西!!!1.调用函数的方法(主要讲语法和格式)2.独立按键如何控制LED亮灭3.程序中的一些细节(软件消抖等)1.调用函数的方法思路还是比较清晰地,就是通过按下按键来控制LED闪灭,即每按下一次,LED取反一次。重要的是,把按键与LED联系在一起。我打算用K1来作为开关,看了一下开发板原理图,K1连接的是单片机的P31口,当按下K1时,P31是与GND相连的,也就是说,当我按下去时

  10. 深度学习部署:Windows安装pycocotools报错解决方法 - 2

    深度学习部署:Windows安装pycocotools报错解决方法1.pycocotools库的简介2.pycocotools安装的坑3.解决办法更多Ai资讯:公主号AiCharm本系列是作者在跑一些深度学习实例时,遇到的各种各样的问题及解决办法,希望能够帮助到大家。ERROR:Commanderroredoutwithexitstatus1:'D:\Anaconda3\python.exe'-u-c'importsys,setuptools,tokenize;sys.argv[0]='"'"'C:\\Users\\46653\\AppData\\Local\\Temp\\pip-instal

随机推荐