C++模板进阶

文章详细介绍了C++中的非类型模板参数,以及模板的特化,包括函数模板和类模板的全特化与偏特化。非类型模板参数允许使用常量作为参数。模板特化用于为特定类型提供不同的实现,函数模板特化和类模板特化有各自的语法和应用场景。全特化为所有模板参数提供特殊化实现,偏特化则对部分模板参数进行特殊处理。文章强调了模板声明与定义应放在一起,以避免编译问题。
摘要由CSDN通过智能技术生成

一.非类型模板参数

模板的参数可以用于传入类型,同时也可以使用常量作为参数

示例:

//N是一个整型
template<typename T, int N>
T* MallocN()
{
	return new T[N];
}

int main()
{
	char* p = MallocN<char,10>();
	return 0;
}
  1. 模板的参数只能是:类型(typename/class),或整型
  2. 非类型的模板参必须显示实例化/缺省值

二. 模板的特化

通常我们使用类模板是因为它可以交由编译器来为我们生成由于类型不同但是功能相同的类

但是当对于某些类型,我们需要特殊处理(实现不同的功能)时,可以进行特化

1.函数模板的特化

  1. 必须先有基础的函数模板
  2. 特化的语法:template<> 函数名<特化类型> ()
  3. 参数列表需要和模板函数保持一致

示例:

template<typename T>
bool Equal(T lhs, T rhs)
{
	return lhs == rhs;
}

//对int*类型进行特化
template<>
bool Equal<int*>(int* lhs, int* rhs)
{
	return *lhs == *rhs;
}

第二个函数,为函数模板的特化,当使用的参数为int*时,则会调用该函数,是对指针指向内容的比较。

但是对于需要特别处理的函数,通常直接显示定义出该函数。使用函数重载来调用。

如:

bool Equal(int* lhs, int* rhs)
{
    return *lhs == *rhs;
}
bool Equal(int** lhs, int** rhs)
{
    return **lhs == **rhs;
}

在调动时会优先调用非模板函数而不会从该模板产生出一个实例

2.类模板的特化

类模板的特化相比于函数模板的特化要复杂的多,通常用来特化解决某一(或某些)需要特殊处理的类型。

不能单独定义一个和类模板名相同的类,像上面函数那样特殊解决。(对于函数,编译器可以根据参数类型来判断调用,同名的类则需要其模板参数类型来判断)。

template<typename T>
class A
{};

A<int> ai;
A<char> ac;

A:是类模板、A< int >A< char >:在是真正的类

类模板特化语法

template<> 
class 类名<特化类型> 
{}
  1. 必须先有基础的类模板
  2. 特化的模板参数个数和类模板保持一致
a.全特化

全特化,即将模板参数列表中所有参数都确定化处理

template<class T1,class T2>
class A
{};

template<>
class A<int, int>
{};

template<>
class A<int, char>
{};

A<int, int>A<int, char>都是根据类模板A全特化出来的,可以在其类体中实现特殊的功能。

//没特化,编译器根据类模板A自动生成对象
A<char, char> acc;

//有特化处理的,会根据其特化的类生成对象
A<int, int> aii;
A<int, char> aic;
b.偏特化

偏特化,即对模板参数列表中的参数进行限制处理

  • 部分参数确定
template<class T1,class T2>
class A
{};

//特化处理
template<class T1>
class A<T1, int>
{};

template<class T2>
class A<int, T2>
{};

使用时,如果能够匹配到特化处理的类模板,则会优先使用特化的

//使用类模板<T1,T2>
A<char, char> acc;

//使用第1个特化的模板,<T1,int>
A<char, int> aci;

//使用第2个特化的模板,<int,T2>
A<int, double> aid;

模板参数名(T1、T2),可以随意定义,无需和基础类模板的保存一致


  • 对参数做限制
template<class T1,class T2>
class A
{};

//特化处理
template<class t1, class t2>
class A<t1*, t2*>
{};

template<class t1, class t2>
class A<t1&, t2&>
{};

下面2个特化处理的类模板,分别针对与当传入的模板参数为指针类型,引用类型时,使用该特化

//使用类模板<T1,T2>
A<char, char> acc;

//使用第1个特化的模板,<t1*,t2*>
A<char*, char*> acc1;

//使用第2个特化的模板,<t1&,t2&>
A<char&, char&> acc2;

对于上述2种偏特化方式,可以根据实际使用场景随意组合

在这里插入图片描述

编译器始终坚持用使用最匹配。

三.模板声明与定义

请保持对于模板(函数模板和类模板)的声明与定义都放在同一个文件中。

一般是放在**.h头文件中,在使用的地方#include " …"包含该头文件即可。或者直接放在使用的.cpp**源文件中。

//声明
template<typename T>
bool Less(T lhs, T rhs);

//定义
template<typename T>
bool Less(T lhs, T rhs)
{
	return lhs < rhs;
}
//声明
template<class T1, class T2>
class A;

//定义
template<class T1, class T2>
class A
{};

对于函数模板,由于编译器对于不同的.cpp源文件是分离编译的,如果在某一个使用函数模板的.cpp中,只有该函数模板的声明。编译器是无法在编译阶段来帮我们根据模板的使用创建不同的函数。因此在链接的时候就会因为找不到函数的定义报错。

对于类(普通类和模板类),是不允许只有定义的。

  • 3
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值