C++中 模板Template的使用

两种模板(C++03) -> 四种模板(C++14)

传统C++只有两种模板,分别是类模板函数模板。而最新的C++标准中总共有四种模板,这是因为C++11引入了别名模板,而C++14则引入了变量模板

template<class T>  和  template<typename T> 都可以用来定义函数模板类模板,在使用上,他们俩没有本质的区别。

具体为;class用于定义类,在模板引入c++后,最初定义模板的方法为:template,这里class关键字表明T是一个类型。后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键字。它的作用同class一样表明后面的符号为一个类型。这样在定义模板的时候就能够使用以下的方式了: template.在模板定义语法中关键字class与typename的作用全然一样。

函数模板针对仅参数类型不同的函数;类模板针对仅数据成员和成员函数类型不同的类。

函数模板:

声明及定义形式为:

template <class 形参名,class 形参名,......> 返回类型 函数名(参数列表)
{
    函数体
}

在头文件

template < class T>
bool compare(T t1, T t2)
{
    if (t1 > t2)
    {
        return true;
    }
    else
    {
        return false;
    }
}

调用的地方: compare<int>(1,2);

延伸到默认模板参数

函数模板的默认模板参数没有此约束。但如果是默认参数值还是要由右到左

template <class T1 = float, int i = 0, class T2 = string>
void funt1(T1 t1, T2 t2 = "bbbb" ) {
	cout << t1 << i<< t2 << endl;
}
 
funt1("a");

template是定义模板函数的关键字;template后面的尖括号不能省略;typename(或class)是声明数据类型參数标识符的关键字。用以说明它后面的标识符是数据类型标识符。这样,在以后定义的这个函数中,凡希望依据实參数据类型来确定数据类型的变量,都能够用数据类型參数标识符来说明,从而使这个变量能够适应不同的数据类型。

如:template <class T> void swap(T& a,T& b){} 

使用函数模板有2种方式

1.自动类型推到调用swap(a,b);

2.显性类型推到调用swap<int>(a,b);

实际应用

int  a =1;

int b= 2;

swap<int>(a,b);

类模板:

其格式为:

template<class  形参名,class 形参名,…>   class 类名
{ ... 
};

foo 为类名,在类定义体中,如採用通用数据类型的成员,函数參数的前面需加上T。当中通用类型T能够作为普通成员变量的类型,还能够作为const和static成员变量以及成员函数的參数和返回类型之用。

如:

template <class T>

class A {

public: 

 T a;
 T b;   
 T hy(T c, T &d);

};

在类A中声明了两个类型为T的成员变量a和b,还声明了一个返回类型为T带两个参数类型为T的函数hy。

用类模板定义对象的写法如下:

类模板名<真实类型参数表> 对象名(构造函数实际参数表);

如果类模板有无参构造函数,那么也可以使用如下写法:

类模板名 <真实类型参数表> 对象名;

template<class T1,class T2> 
class A 
{
public:
    T1 g(T1 a, T2 b);
    A();
};

template<class T1, class T2>
A<T1, T2>::A()
{

}

template<class T1, class T2>
T1 A<T1, T2>::g(T1 a, T2 b)
{
    return a + b;
}

int main()
{
     A<float, int> ta;
    ta.g(1.1, 2);
    return 0;
}

进一步研究:类模板与继承

1.当子类不是类模板,而继承的父类是一个类模板时,子类在声明的时候要指定出父类中的类型

//类模板与继承
template<typename T>
class Basic {
public:
	T age;
};

 子类不是类模板时,可以直接调用基类类模板的函数,因为基类的模板类型已经指定了

//此处需要指定父类中的模板数据类型
class t1 :public Basic<string> {

};
void func1() {
	t1 ttt;
	ttt.age = "abc";
	cout << ttt.age << endl;
}

 2.子类是类模板,继承的父类也是一个类模板时。

template <class T>
class tem {
public:
	T  aa;
	int bb;
	void func(T t);
	void funct() {
		int dd = 1;
	}
};


template <class T1,class T2>
class tem3 :public tem<T1>
{
public:
	using tem<T1>::funct;
	int cc;

	T2  dd;
	void functem3() {
		funct();
	}

};
	tem3<int, int> tt3;
	tt3.functem3();

3. 类模板的默认模板参数需要从右到左依次;

template <class T1 = int, int i = 0, class T2 = string>
class ctem
{
public:
    T1 t1;
    void fun1(T2 t2);
};
 
template <class T1 /*= int*/, int i /*= 0*/, class T2 /*= string*/>
void ctem<T1, i, T2>::fun1(T2 t2)
{
 
}
ctem<> tem;
tem.fun1("q");

4.当子类类模板调用基类模板的函数时:直接调用会报错,见下图

解决办法可以有3种办法:
1.在调用动作之前加上“this->”
2.使用using声明式(using tem<T1>::funct;)
3.明白指出被调用的函数位于base class内(baseclass::func())最好不用这办法,因为实现不了虚函数的多态。

别名模板(alias template)
别名模板:带模板参数的类型别名
类型别名(type alias)是C++11新引入的语法形式:
using newtype = oldtype;
在语法功能上,它相当于传统C/C++语言中的typedef语句:
typedef oldtype newtype;
可以看出,类型别名中原有类型和别名的定义顺序与typedef语句正好相反。除此之外,类型别名与typedef语句还有一点不同,类型别名可以加上模板参数形成别名模板:
template<typename ...> using newtype = oldtype<...>;
注:C++11引入类型别名意图取代typedef语句的原因在于:无法直接在typedef语句的基础上直接构建别名模板。这是因为typedef语句自身存在某些局限性,直接给typedef加上模板参数会带来语法解析上的问题。

template<typename T, typename U>
struct A;
 
template<typename T>
struct B
{
    typedef A<T, int> type;
};
 
template<typename T> using C = A<T, int>;
 
template<typename T> using D = typename B<T>::type;

代码说明:
假设我们有一个带两个模板参数T和U的类模板A。现在我们需要声明一个只带一个模板参数T的类模板,使其等价于模板参数U为int类型的A模板。也就是说,我们需要一个模板参数T任意,模板参数U为int类型的A模板的别名,或者说A<T, int>的别名。
在C++11之前,答案为类模板B。要定义类型别名,必然要使用typedef。但由于typedef不能带模板参数,所以typedef必须被嵌入到一个带模板参数的类模板里面。在模板参数为T的类模板B里面,类型type被定义成A<T, int>的别名。也就是说typename B<T>::type被定义成了A<T, int>的别名。
在C++11之后,答案为别名模板C。类型别名直接就可以带模板参数。C<T>直接被定义成了A<T, int>的别名。
如果出于某种原因,在定义别名的时候无法使用类模板A而只能使用类模板B,别名模板也能发挥作用。这里D<T>直接被定义成了typename B<T>::type的别名。由于后者是A<T, int>的别名,所以D<T>其实也是A<T, int>的别名。
这段代码展示了别名模板的主要用途:1.为部分模板参数固定的类模板提供别名。2.为类模板中嵌入的类型定义提供别名。

变量模板(variable template)
变量模板:变量的家族
变量模板是C++14新引入的模板形式,在语法功能上它相当于一个没有参数但是有返回值的函数模板,相对于后者,变量模板在语法上更清晰,更能反映编程者的意图。
template<typename ...> type variable;

#include <iostream>
#include <iomanip>
using namespace std;
// 函数模板
template<class T>
constexpr T pi_fn()
{
    return T(3.1415926535897932385);
}
// 变量模板
template<class T>
constexpr T pi = T(3.1415926535897932385);
 
int main()
{
   cout << pi_fn<int>() << pi<int> << '\n'; // 33
   cout << setprecision(10) << pi<float> << '\n'; // 3.141592741
   cout << setprecision(10) << pi<double> << '\n'; // 3.141592654
}

  • 3
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值