admin管理员组文章数量:1031774
【c++指南】模板VS手写代码:这场效率对决你站哪边?【上】
引入
泛型编程
在如上一段代码中,写了一个Swap函数,为了多种类型的支持,因此通过函数重载达到了多种类型的变量的交换。但是,如果此时增加一个新类型:如float类型或者类类型时,又需要程序员再增加自己对应的的函数。
- 这是非常麻烦且代码复用性较低。每当出现新类型,都需要手动增加新函数;
- 代码的维护性低,一旦某个位置出错,其余的函数重载都得改动。
很显然,这种方式不是我们所期望的。那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。换句话说,有了函数重载的支持,才能达到模板的目的。
模板相当于一个模具,通过这个模具能填充不同类型,生成不同的的类型的代码。如同在古代没有造纸术时,只能依赖刀具处理木牍、竹简生成对应的模具;但当蔡伦发明了造纸术后,有了抄纸的模具“帘床”,大大提高了效率。
函数模板
概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生
函数的特定类型版本。
格式
小编带着瞅瞅stl模板库中基本都是模板来实现的。
从这里就可以发现模板的妙处,编译器能通过我们写的变量自动推导类型,生成不同的函数。那模板的格式又是咋样的呢?
template<typename T1, typename T2,......,typename Tn>
(typename也可写成class,大多情况上是没区别的)
返回值类型 函数名 ( 参数列表 ){}
代码语言:javascript代码运行次数:0运行复制//template<typename T>
template<class T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。
所以其实 模板就是将本来应该我们做的重复的事情交给了编译器来做。
在编译器编译阶段 ,对于模板函数的使用, 编译器需要根据传入的实参类型来推演生成对应
类型的函数 以供调用。比如: 当用 double 类型使用函数模板时,编译器通过对实参类型的推演,
将 T 确定为 double 类型,然后产生一份专门处理 double 类型的代码 ,对于字符类型也是如此。
函数模板实例化
用不同类型的参数使用函数模板时 ,称为函数模板的 实例化 。模板参数实例化分为: 隐式实例化
和显式实例化 。
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
代码语言:javascript代码运行次数:0运行复制template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
return 0;
}
在上面的程序就是隐式实例化(编译器自动识别参数类型)的体现。
那如果left是int类型,right是double类型呢?编译器又是否能够自动识别类型?
这里的报错信息是未找到匹配的重载函数,为什么呢?
因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1 将 T 推演为 int ,通过实参 d1 将 T 推演为 double 类型,但模板参数列表中只有一个T , 编译器无法确定此处到底该将T 确定为 int 或者 double 类型而报错。(编译器一般不会对类型进行强转)
那有什么解决方法呢?
- 自己手动强转从而来匹配对应的重载函数;
- 使用显式实例化。
2. 显式实例化:在函数名后的 <> 中指定模板参数的实际类型
代码语言:javascript代码运行次数:0运行复制Add<int>(a, b);
匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这 个非模板函数。
2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而 不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。(即编译器有现成的会吃现成的,不会去推演)
那如果非要调用模板函数呢?使用显式实例化。
代码语言:javascript代码运行次数:0运行复制int Add(int left, int right)
{
return left + right;
}
template<class T>
T Add(T left, T right)
{
return left + right;
}
Add(1, 2);
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
前言
在实现顺序表、链表等数据结构时,我们常常使用
代码语言:javascript代码运行次数:0运行复制typedef + 类型 + 命名;
但是这种只能支持一种类型,即类型如果写成int,就只能插入int类型的数据;如果写成double类型,就只能插入double类型的数据。有没什么方法可以让这个类实现多个类型呢?那就需要引入类模板的概念。
类模板
定义格式
代码语言:javascript代码运行次数:0运行复制template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
代码语言:javascript代码运行次数:0运行复制// 类模版
template<class T>
class Stack
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
void Push(const T& data)
{
//...
}
private:
T* _array;
size_t _capacity;
size_t _size;
};
在上面一段程序中,写了一段Stack类模板,可以支持多种类型的类。表面上看,我们只写了一份类模板,但实际编译器需要根据不同类型生成不同类型的类。这种方式极大减少了程序员敲代码的痛苦,脏活累活都交给了编译器来处理。
并且,模板并不推荐声明和定义分离到两个文件.h 和.cpp,这样会出现链接错误。(后续会讲)
类模板实例化
类模板实例化与函数模板实例化不同, 类模板实例化需要在类模板名字后跟 <> ,然后将实例化的
类型放在 <> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类 。
代码语言:javascript代码运行次数:0运行复制// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-05,如有侵权请联系 cloudcommunity@tencent 删除效率c++编译器泛型函数【c++指南】模板VS手写代码:这场效率对决你站哪边?【上】
引入
泛型编程
在如上一段代码中,写了一个Swap函数,为了多种类型的支持,因此通过函数重载达到了多种类型的变量的交换。但是,如果此时增加一个新类型:如float类型或者类类型时,又需要程序员再增加自己对应的的函数。
- 这是非常麻烦且代码复用性较低。每当出现新类型,都需要手动增加新函数;
- 代码的维护性低,一旦某个位置出错,其余的函数重载都得改动。
很显然,这种方式不是我们所期望的。那能否告诉编译器一个模子,让编译器根据不同的类型利用该模子来生成代码呢?
泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。换句话说,有了函数重载的支持,才能达到模板的目的。
模板相当于一个模具,通过这个模具能填充不同类型,生成不同的的类型的代码。如同在古代没有造纸术时,只能依赖刀具处理木牍、竹简生成对应的模具;但当蔡伦发明了造纸术后,有了抄纸的模具“帘床”,大大提高了效率。
函数模板
概念
函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生
函数的特定类型版本。
格式
小编带着瞅瞅stl模板库中基本都是模板来实现的。
从这里就可以发现模板的妙处,编译器能通过我们写的变量自动推导类型,生成不同的函数。那模板的格式又是咋样的呢?
template<typename T1, typename T2,......,typename Tn>
(typename也可写成class,大多情况上是没区别的)
返回值类型 函数名 ( 参数列表 ){}
代码语言:javascript代码运行次数:0运行复制//template<typename T>
template<class T>
void Swap(T& left, T& right)
{
T temp = left;
left = right;
right = temp;
}
原理
函数模板是一个蓝图,它本身并不是函数,是编译器用使用方式产生特定具体类型函数的模具。
所以其实 模板就是将本来应该我们做的重复的事情交给了编译器来做。
在编译器编译阶段 ,对于模板函数的使用, 编译器需要根据传入的实参类型来推演生成对应
类型的函数 以供调用。比如: 当用 double 类型使用函数模板时,编译器通过对实参类型的推演,
将 T 确定为 double 类型,然后产生一份专门处理 double 类型的代码 ,对于字符类型也是如此。
函数模板实例化
用不同类型的参数使用函数模板时 ,称为函数模板的 实例化 。模板参数实例化分为: 隐式实例化
和显式实例化 。
1. 隐式实例化:让编译器根据实参推演模板参数的实际类型
代码语言:javascript代码运行次数:0运行复制template<class T>
T Add(const T& left, const T& right)
{
return left + right;
}
int main()
{
int a1 = 10, a2 = 20;
double d1 = 10.0, d2 = 20.0;
Add(a1, a2);
Add(d1, d2);
return 0;
}
在上面的程序就是隐式实例化(编译器自动识别参数类型)的体现。
那如果left是int类型,right是double类型呢?编译器又是否能够自动识别类型?
这里的报错信息是未找到匹配的重载函数,为什么呢?
因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1 将 T 推演为 int ,通过实参 d1 将 T 推演为 double 类型,但模板参数列表中只有一个T , 编译器无法确定此处到底该将T 确定为 int 或者 double 类型而报错。(编译器一般不会对类型进行强转)
那有什么解决方法呢?
- 自己手动强转从而来匹配对应的重载函数;
- 使用显式实例化。
2. 显式实例化:在函数名后的 <> 中指定模板参数的实际类型
代码语言:javascript代码运行次数:0运行复制Add<int>(a, b);
匹配原则
1. 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这 个非模板函数。
2.对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而 不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数, 那么将选择模板。(即编译器有现成的会吃现成的,不会去推演)
那如果非要调用模板函数呢?使用显式实例化。
代码语言:javascript代码运行次数:0运行复制int Add(int left, int right)
{
return left + right;
}
template<class T>
T Add(T left, T right)
{
return left + right;
}
Add(1, 2);
3. 模板函数不允许自动类型转换,但普通函数可以进行自动类型转换
前言
在实现顺序表、链表等数据结构时,我们常常使用
代码语言:javascript代码运行次数:0运行复制typedef + 类型 + 命名;
但是这种只能支持一种类型,即类型如果写成int,就只能插入int类型的数据;如果写成double类型,就只能插入double类型的数据。有没什么方法可以让这个类实现多个类型呢?那就需要引入类模板的概念。
类模板
定义格式
代码语言:javascript代码运行次数:0运行复制template<class T1, class T2, ..., class Tn>
class 类模板名
{
// 类内成员定义
};
代码语言:javascript代码运行次数:0运行复制// 类模版
template<class T>
class Stack
{
public:
Stack(size_t capacity = 4)
{
_array = new T[capacity];
_capacity = capacity;
_size = 0;
}
void Push(const T& data)
{
//...
}
private:
T* _array;
size_t _capacity;
size_t _size;
};
在上面一段程序中,写了一段Stack类模板,可以支持多种类型的类。表面上看,我们只写了一份类模板,但实际编译器需要根据不同类型生成不同类型的类。这种方式极大减少了程序员敲代码的痛苦,脏活累活都交给了编译器来处理。
并且,模板并不推荐声明和定义分离到两个文件.h 和.cpp,这样会出现链接错误。(后续会讲)
类模板实例化
类模板实例化与函数模板实例化不同, 类模板实例化需要在类模板名字后跟 <> ,然后将实例化的
类型放在 <> 中即可,类模板名字不是真正的类,而实例化的结果才是真正的类 。
代码语言:javascript代码运行次数:0运行复制// Stack是类名,Stack<int>才是类型
Stack<int> st1; // int
Stack<double> st2; // double
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2025-04-05,如有侵权请联系 cloudcommunity@tencent 删除效率c++编译器泛型函数本文标签: c指南模板VS手写代码这场效率对决你站哪边上
版权声明:本文标题:【c++指南】模板VS手写代码:这场效率对决你站哪边?【上】 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://it.en369.cn/jiaocheng/1747884555a2222541.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论