C++ template 学习归纳2

关于c++中的类模板,常见的形式为:

template<typename T>
class className{
	//...
};

比如笔者在这里举一个例子:

 

#include <iostream>
#include<vector>
#include <stdexcept>

template<typename T>
class stack{
private:
	std::vector<T> elems;
public:
	void push(T const&);
	void pop();
	T top() const;
	bool empty() const{
		return elems.empty();
	}
};

template<typename T>
void stack<T>::push(T const& a){
	elems.push_back(a);
}

template<typename T>
void stack<T>::pop(){
	if(elems.empty()){
		throw std::out_of_range("stack<T>::pop empty");
	}
	return elems.pop_back();
}

template<typename T>
T stack<T>::top()const{
	if(elems.empty()){
		throw std::out_of_range("stack<T>::top empty");
	}
	return elems.back();
}

int main(){

	return 0;
}

从上面的代码可以看出,为了定义成员函数,我们使用了下面的形式,比如:

template<typename T>
void stack<T>::push(T const& a){
	elems.push_back(a);
}

本来在此处有一个问题的,也就是关于类成员函数的实现位置的问题,这个问题我们稍后会提到。

现在我们为了测试上面的例子可以使用下面的函数代码:

int main(){
	stack<int> intStack;
	intStack.push(1);
	intStack.push(2);
	std::cout<<intStack.top()<<std::endl;

	stack<std::string> strStack;
	strStack.push("hello");
	std::cout<<strStack.top()<<std::endl;
	return 0;
}

我们有些时候会遇到这样的代码,比如:

stack<stack<int> > intStack;

在这种情况下,我们要注意就是两个“>”中间的那个空格,那个是必须的,否则的话,编译器会认为是“>>”。这一点大家写代码的时候要注意。

下面我们来看看类模板的特化:

当我们想特化一个类模板的时候,我们就需要用template<>开头,后面更上我们希望特化的代码。比如:

template<>
class myStack<std::string>{
	//...
};

对于特化类模板而言,就如同编写普通的类成员函数一样,比如:

void myStack<int>::pop(int const& a){
	//...
}

下面我们呢来看看类模板的局部特化。

例如对于下面的代码:

template<typename T1,typename T2>
class myClass{
	/...
};

而言,以下几种像是的局部特化都是正确 的:

//局部特化 两个参数一致
template<typename T>
class myClass<T,T>{
	//...
};

//局部特化 第二个为int
template<typename T>
class myClass<T,int>{
	//...
};

//两个参数都为指针类型
template<typename T1,typename T2>
class myClass<T1*,T2*>{
	//...
};

在下面的例子中:

myClass<int float>mif; //将使用<T1,T2>
myClass<float,float>mif; //将使用<T>
myClass<float,int>mif;  //将使用<T,int>
myClass<int*,double*>mp;  //将使用<T1*,T2*>

大家要注意下面的错误代码,

myClass<int,int>m;
myClass<int*,int*>m;

z这两个代码在上面的这个例子中都是错误的。前者因为会和myClass<T,T>产生二义性。后者会和myClass<T,T>产生二义性、使得编译器不知道应该匹配哪一个。

如果想解决上面的第二个二义性的话,我们可以专门特化下面的代码:

template<typename T>
class myClass<T*,T*>{
	//...
};

接下来我们来看看预设模板参数:

我们先来看看代码再说,大家注意和上面的例子进行比较:

#include <iostream>
#include<vector>
#include <deque>
#include <cstdlib>
#include <stdexcept>

template<typename T,typename CONT=std::vector<T> >
class stack{
private:
	CONT elems;
public:
	void push(T const&);
	void pop();
	T top() const;
	bool empty() const{
		return elems.empty();
	}
};

template<typename T,typename CONT>
void stack<T,CONT>::push(T const& a){
	elems.push_back(a);
}

template<typename T,typename CONT>
void stack<T,CONT>::pop(){
	if(elems.empty()){
		throw std::out_of_range("stack<T>::pop empty");
	}
	return elems.pop_back();
}

template<typename T,typename CONT>
T stack<T,CONT>::top()const{
	if(elems.empty()){
		throw std::out_of_range("stack<T>::top empty");
	}
	return elems.back();
}

int main(){
	try{
		stack<int> intStack;
		stack<double,std::vector<double> > douStack;
		//注意,这里千万不能写下面的这一行代码:
		// stack<double,std::vector<int> > douStack;

		intStack.push(1);
		std::cout<<intStack.top()<<std::endl;

		douStack.push(1.1);
		std::cout<<douStack.top()<<std::endl;
	}catch(std::exception const& ex){
		std::cerr<<ex.what()<<std::endl;
		return EXIT_FAILURE;
	}
	return 0;
}

我们使用

	stack<double,std::vector<double> > douStack;

来声明了一个double stack,他的内部使用的是std:eque<>来管理。

时间: 2024-12-06 08:03:47

C++ template 学习归纳2的相关文章

C++ template 学习归纳总结4

我们在这篇文章来说说typename关键字吧.这个关键字是在c++的标准化过程中引入的,目的在于说明template中的某个表示符号是一个类型,而不是其他的东西,看下面的代码: template <typename T> class MyClass { typename T::SubType * ptr; - }; 第一个typename我就不多说了,大家都知道,我来说一下第二个.他的意思是说T::SubType是class T内部定义的一个类型,从而ptr是一个指向[T:SubType类型]

C++ template学习总结6

对于基本类型来说,并没有一个default模式来讲他们初始化为有意义的值,没有初始化的变量,其指都是未定义的,但是在模板这一块呢?我们可以采用下面的形式: template <typename T> void foo() { T x = T(); // x is zero (or false)ifT is a built-in type } 对于class template我们可以采用下面例子的方式: template <typename T> class MyClass { pr

c++ template学习总结3

和往常一样,先来看一段代码: #include <stdexcept> template <typename T, int MAXSIZE> class Stack { private: T elems[MAXSIZE]; // elements int numElems; // current number of elements public: Stack(); // constructor void push(T const&); // push element vo

jQuery .tmpl(), .template()学习资料小结_jquery

昨晚无意中发现一个有趣的jQuery插件.tmpl(),其文档在这里.官方解释对该插件的说明:将匹配的第一个元素作为模板,render指定的数据,签名如下: .tmpl([data,][options]) 其中参数data的用途很明显:用于render的数据,可以是任意js类型,包括数组和对象.options一般情况下都是选项了,官方指出,此处的options是一个用户自定义的键值对的map,继承自tmplItem数据结构,适用于模板render动作期间. 在这里可以下载到最新的tmpl插件,值

快速读懂机器学习(附送详细学习资源)

前言: 机器学习作为人工智能中的伟大分支,让我们先来聊聊人工智能把.现在人工智能已经非常普遍了,从之前的阿尔法狗到现在中国人工智能机器人解答北京高考数学卷 考了105分.以及2017.6.6的苹果WWDC大会上宣布开发机器学习API,苹果想通过借此之举,让更过苹果开发者用户开发出更过用户体验好的应用,人工智能的例子真是数不胜数,已经渗透到我们生活的各方各面,比较常见的比如金融以及医疗,而且之前看了一篇文章这样评价金融业:随着人工智能的发展与普遍,以后金融业对求职者的要求需要掌握人工智能相关知识来

AI 初学者入门指南:深度学习的五级分类

目前 AI 被笼统划分为"弱人工智能"."强人工智能"."超人工智能"三个类别.甚至在很多业内专家(比如洪小文)眼中,只有"强"."弱"AI 的区别,因为"超人工智能"离我们实在还很远,难以捉摸.这样的笼统分类显然不利于大众对于各项 AI 技术进行认识和理解.因此,一些专家开始提出基于技术难度和 AI 智能水平的分类.分级方法. 其中,美国学者 Arend Hintze 提出了对 AI

机器学习——随机森林算法及原理

1. 随机森林使用背景 1.1 随机森林定义 随机森林是一种比较新的机器学习模型.经典的机器学习模型是神经网络,有半个多世纪的历史了.神经网络预测精确,但是计算量很大.上世纪八十年代Breiman等人发明分类树的算法(Breiman et al. 1984),通过反复二分数据进行分类或回归,计算量大大降低.2001年Breiman把分类树组合成随机森林(Breiman 2001a),即在变量(列)的使用和数据(行)的使用上进行随机化,生成很多分类树,再汇总分类树的结果.随机森林在运算量没有显著提

深度 | 人工智能全局概览:通用智能的当前困境和未来可能

我们的未来将不可避免地与人工智能捆绑在一起,于是我们就必须要问:人工智能的现状是怎样的?我们将走向何方?(可点击阅读原文下载原版 PDF) 目录 如今人工智能的能力和局限 迈向通用人工智能 训练还是不训练 智能的意义 助理还是主角? 为何人们对人工智能的兴趣大增? 建立知识数据库 产生结果 道德和未来 总是在未来 定义人工智能不是困难,而简直是不可能,这完全不是因为我们并不理解人类智能.奇怪的是,人工智能的进步更多的将帮助我们定义人类智能不是什么,而不是定义人工智能是什么? 但不管人工智能是什么

中国人工智能学会通讯——智能交互开启未来

我讲的内容可能跟刘博士有一部分是重复的.因为之前我们一直做语义理解,语音识别厂商一直在做语音,后来大家发现它们密不可分,所以一直在融合.我们现在在找语音方面的一些合作伙伴,语音厂商也往语义方面去做. 人工智能,对于普通的群众来说就是变形金刚,就是终结者.可是在产业界,我们就会想到自动驾驶,还有机器识别,还有类似的智能交互,还有AlphaGO.人工智能其实不是全能的,只是在某一个方向.某一个方面去解决一定的问题.我们怎么去定义人工智能?现在人工智能没有一个非常明确的定义,没有非常明确官方的定义,因