模板(一):模板与非类型模板参数&模板的模板参数

活着就意味必须要做点什么,请好好努力。
                             ------《地下》

函数模板&类模板

模版是泛型编程的基础, 模版分为 函数模版 和 类模版

函数模板格式:

template <class(或typename) 形参名1, class 形参名2, class 形参名n>
返回类型 函数名(参数列表)
{...}

模板形参的定义既可以使用class,也可以使用typename,含义是相同的.

//一个简单的函数模板,比较 left 和 right, 与类型无关
template<typename T>
bool IsEqual (const T& left , const T& right )
{
	return left == right;
}

void test1 ()
{
	string s1 ("s1"), s2("s2" );
	IsEqual (s1, s2);
	IsEqual (1,1);
}

模板(一):模板与非类型模板参数&模板的模板参数_第1张图片

模板参数匹配及显示实例化

template <typename T>
bool IsEqual (const T& left , const T& right )
{
	return left == right;
}

void test1 ()
{
	cout<<IsEqual (1,1)<<endl;
	//cout<
	cout<<IsEqual<int>(1,1.2)<< endl; // 显示实例化
	cout<<IsEqual<double>(1,1.2)<< endl; // 显示实例化
}

重载函数模板

bool IsEqual (const int& left , const int& right)
{
	return left == right;
}

template <typename T>
bool IsEqual (const T& left , const T& right )
{
	return left == right;
}

template <typename T1, typename T2>
bool IsEqual (const T1& left , const T2& right)
{
	return left == right;
}

void test1 ()
{
	cout<<IsEqual(1,1)<<endl;
	cout<<IsEqual<int>(1,1)<< endl;
	cout<<IsEqual(1,1.2)<<endl;
}

函数会 优先调用 最适合自己的函数
函数模板重载四大规则

  1. 函数模板可以像普通函数一样被重载
  2. C++编译器优先考虑普通函数
  3. 如果函数模板可以产生一个更好的匹配,那么选择模板
  4. 可以通过空模板实参列表<>的语法限定编译器只通过模板匹配

类模版格式:

template <class 形参名1, class 形参名2, ...class 形参名n>
class 类名
{ ... }

模板类实例

//动态顺序表
template<typename T>
class SeqList
{
public :
	SeqList();
	~ SeqList();
private :
	int _size ;
	int _capacity ;
	T* _data ;
};

template <typename T>
SeqList <T>:: SeqList()
	: _size(0)
	, _capacity(10)
	, _data(new T[ _capacity])
{}

template <typename T>
SeqList <T>::~ SeqList()
{
	delete [] _data ;
}

void test1 ()
{
	SeqList<int> sl1;
	SeqList<double> sl2;
}

模板(一):模板与非类型模板参数&模板的模板参数_第2张图片
模板类的实例化
类模板是用来生成类的蓝图的。
与函数模板的不同之处是:编译器不能为类模板推断模板参数类型。为了使用类模板,我们必须在模板名后的尖括号中提供额外信息——用来代替模板参数的模板实参列表。

##非类型模板参数&模板的模板参数

####模板参数–实现容器适配器

template 
class SeqList
{
private :
	int _size ;
	int _capacity ;
	T* _data ;
};

// template 
template  > // 缺省参数
class Stack
{
public :
	void Push (const T& x );
	void Pop ();
	const T & Top();
	bool Empty ();
private :
	Container _con ;
};

void Test ()
{
	Stack s1;
	Stack> s2 ;
// 思考下面这种使用场景会怎样?
	Stack> s3 ;
}

####模板的模板参数–容器适配器

template <typename T>
class SeqList
{
private :
	int _size ;
	int _capacity ;
	T* _data ;
};

// template  class Container>
template <class T, template <class> class Container = SeqList > // 缺省参数
class Stack
{
public :
	void Push (const T& x );
	void Pop ();
	const T & Top();
	bool Empty ();
private :
	Container<T > _con;
};

void Test ()
{
	Stack<int > s1;
	Stack<int , SeqList> s2;
}

模板(一):模板与非类型模板参数&模板的模板参数_第3张图片

####非类型的类模板参数

// 静态顺序表
//template
template <typename T, size_t MAX_SIZE = 10> //带缺省模板参数
class SeqList
{
public :
	SeqList();
private :
	T _array [MAX_SIZE];
	int _size ;
};

template <typename T, size_t MAX_SIZE>
SeqList <T, MAX_SIZE>::SeqList ()
	: _size(0)
{}

void Test ()
{
	SeqList<int > s1;
	SeqList<int , 20> s2;
}

####非类型的模板函数参数

template 
T Add (const T& x )
{
	return x + value;
}

浮点数和类对象是不允许作为非类型模板参数的

//template	//error
template 	//error
class Test
{
private :
	double _value ;
};

补充:
C++ 中 typename 和 class 的区别

在 C++ Template 中很多地方都用到了 typename 与 class 这两个关键字,而且好像可以替换,是不是这两个关键字完全一样呢?
  相信学习 C++ 的人对 class 这个关键字都非常明白,class 用于定义类,在模板引入 c++ 后,最初定义模板的方法为:

template<class T>......

这里 class 关键字表明T是一个类型,后来为了避免 class 在这两个地方的使用可能给人带来混淆,所以引入了 typename 这个关键字,它的作用同 class 一样表明后面的符号为一个类型,这样在定义模板的时候就可以使用下面的方式了:

template<typenameT>......

在模板定义语法中关键字 class 与 typename 的作用完全一样。

typename 难道仅仅在模板定义中起作用吗?其实不是这样,typename 另外一个作用为:使用嵌套依赖类型(nested depended name),如下所示:

class MyArray 
{ 
    publictypedef int LengthType;
.....
}

template<class T>
void MyMethod( T myarr ) 
{ 
    typedef typename T::LengthType LengthType; 
    LengthType length = myarr.GetLength; 
}

这个时候 typename 的作用就是告诉 c++ 编译器,typename 后面的字符串为一个类型名称,而不是成员函数或者成员变量,这个时候如果前面没有 typename,编译器没有任何办法知道 T::LengthType 是一个类型还是一个成员名称(静态数据成员或者静态函数),所以编译不能够通过。

模板(二):模板的特化与模板的分离编译
模板(三):模板之类型萃取(TypeTraits)

你可能感兴趣的:(C,plus,plus)