C++08函数模板
创始人
2024-03-14 08:05:45
0

1.自动推导类型

在C语言和C++98中,auto 关键字用于修饰变量(自动存储的局部变量)。

在C++11中,赋予了auto 全新的含义,不再用于修饰的变量,而是作为一个类型指示符,指示编译器在编译时推导auto声明的变量的数据类型。

在Linux 平台下,编译需要加-std=c++11 参数。

#include 
using namespace std;// 如果初始化变量的时候不定义类型,那么会使用auto关键字
// 根据变量赋值,自动推导出相关类型
int main() {auto a = 3; cout << "a=" << a << endl;auto b = 3.3; cout << "b=" << b << endl;auto c = "鲁班"; cout << "c =" << c << endl;system("Pause");
}

 注意事项:

  1. auto声明的变量必须在定义时初始化
  2. 初始化的右值可以是具体的数值,也可以是表达式和函数的返回值等
  3. auto不能作为函数的形参类型
  4. auto不能直接声明数组
  5. auto不能定义类的非静态成员变量

 auto关键字的真正用途:

  1. 代替冗长复杂的变量声明
  2. 在模板中,用于声明依赖模板参数的变量。
  3. 函数模板依赖模板参数的返回值
  4. 用于lambda 表达式中

 auto关键字可以计算两个不同类型的值

#include 
using namespace std;template
void func(T1 x, T2 y) {auto tmp = x + y;cout << tmp << endl;
}int main() {short a = 1;char b = 2;func(a, b);system("Pause");return 0;
}

2.函数模板

 先看一段代码:如果我们需要更换两个变量的值,根据变量值的不同,需要不断的重载Swap函数,函数中的tmp变量类型也会改变,其他地方都一样。

#include 
using namespace std;// 交换两int值
void Swap(int &a ,int &b) {int tmp = a;b = a;a = tmp;
}// 交换两double值
void Swap(double& a, double& b) {double tmp = a;b = a;a = tmp;
}// 交换两字符串值
void Swap(string& a, string& b) {string tmp = a;b = a;a = tmp;
}int mian() {}

为了避免这种麻烦,利用模型来生成相应的函数代码,即函数模板:

  1. 函数模板是通用的函数描述,使用任意类型(泛型)来描述函数
  2. 编译的时候,编译器推导实参的数据类型,根据实参的数据类型和函数模板,生成该类型的函数定义
  3. 生成函数定义的过程被称为实例化。

创建交换两个变量的函数模板:

#include 
using namespace std;// 创建一个函数模板,交换两个变量的值
// 定义模板,这里anytype可以随便取名,但是需要注意和下面一致
// 函数模板用typename  类模板用 class
template 
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;
}int main() {int a = 1, b = 2;cout << a << b << endl;Swap(a, b);cout << a << b << endl;system("Pause");return 0;  }

注意事项:

  1. 可以为类的成员函数创建模板,但不能是虚函数和析构函数
  2. 使用函数模板时,必须明确数据类型,确保实参与函数模板能匹配上
  3. 使用函数模板时,推导的数据类型必须适应函数模板中的代码
  4. 使用函数模板时,如果是自动类型推导,不会发生隐式类型转换,如果显式指定了函数模板的数据类型,可以发生隐式类型转换
  5. 函数模板支持多个通用数据类型的参数
#include 
using namespace std;class Fruit {
public:// 构造函数template Fruit(T a) {cout << "a=" << a << endl;}// 用到模板的地方在上面都要加这一句template void show(T1 b,T2 c) {cout << "b=" << b << endl;cout << "c=" << c << endl;}
};int main() {Fruit apple("烟台红苹果");apple.show("真的甜","好吃");system("Pause");return 0;  }

 函数模板的具体化

语法:

template<>void 函数模板名<数据类型>(参数列表)

template<>void 函数模板名(参数列表)

{

     // 函数体

}

#include 
using namespace std;class Fruit {
public:// 构造函数Fruit(const string& f_name,int f_gram) {m_gram = f_gram;m_name = f_name;}void show_gram() {cout << this->m_name << this->m_gram << endl;}string m_name;int m_gram;
};// 函数模板
template
void Swap(T& a, T& b) {T tmp = a;a = b;b = tmp;cout << "调用了Swap(T& a, T&b)" << endl;
}//具体化函数
template<>void Swap(Fruit& f1, Fruit& f2) {int tmp = f1.m_gram;f1.m_gram = f2.m_gram;f2.m_gram = tmp;cout << "调用了Swap(Fruit& f1, Fruit& f2)" << endl;
}int main() {Fruit apple("苹果", 12), orange("橘子", 55);apple.show_gram();orange.show_gram();Swap(apple, orange);apple.show_gram();orange.show_gram();system("Pause");return 0;  }

  1. 具体化优先于常规模板,普通函数优先于具体化
  2. 如果希望使用函数模板,可以用空模板参数强制使用函数模板
  3. 如何函数模板能产生更好的匹配,将优先于非函数模板

声明和定义分开

函数模板的定义和声明都是在头文件中,普通函数和函数模板的具体化版本是分开的。

main.cpp

#include 
#include"public.h"
using namespace std;int main() {Swap(1, 1);  // 使用普通函数Swap('c', 'd');  // 使用函数模板Swap<>(1, 1);  // 使用函数模板具体化版本system("Pause");return 0;
}

 头文件public.h:

#pragma once
#include 
using namespace std;void Swap(int a, int b);  // 普通函数template   // 函数模板
void Swap(T a, T b) {cout << "使用了函数模板" << endl;
}template<>
void Swap(int a, int b); // 函数模板具体化版本

源文件public.cpp

#include "public.h"void Swap(int a, int b) {cout << "使用了普通函数" << endl;
}template<>
void Swap(int a, int b) {cout << "使用了具体化的函数模板" << endl;
}

3.类模板

template

class 类模板名

{

        类的定义

}

#include 
using namespace std;template
class AA {
public:T1 m_a;T2 m_b;AA(T1 a, T2 b) :m_a(a), m_b(b){}//构造函数AA() {}// 可以用于成员函数的返回值// 即a是什么类型,这里geta返回的也是什么类型T1 geta() {T1 num = 2; // 这里也可以定义一个和a相同类型的与a相加return m_a + num;}T2 getb() {T1 num = 2;return m_b;}};int main() {AAa;  // 用模板类AA创建对象a.m_a = 2;a.m_b = 3;cout << "a.geta()=" << a.geta() << endl;cout << "a.getb()=" << a.getb() << endl;system("Pause");return 0;
}

可以用new创建模板类对象:main函数这么写

int main() {AA*a=new AA(1,2);  // 用模板类AA创建对象cout << "a.geta()=" << a->geta() << endl;cout << "a.getb()=" << a->geta() << endl;delete a;system("Pause");return 0;
}

类模板的具体化

#include 
using namespace std;//类模板
template
class AA {T1 mx;T2 my;AA(const T1 x, const T2 y) :mx(x), my(y) { cout << "类模板,构造函数" << endl; }void show()const;//类内声明,类外实现
};// 成员函数类外实现
template
void AA::show()const {cout << "类模板:x=" << mx << ",y=" << my << endl;
};//类模板完全具体化
template<>class AA {
public:int mx;string my;AA(const int x, const string y) :mx(x), my(y) { cout << "完全具体化:构造函数" << endl; };void show()const;
};void AA::show()const {cout << "完全具体化x=" << mx << ",y=" << my << endl;
};//类模板部分显示具体化
template
class AA {  // T1通用,string具体
public:T1 mx;string my;AA(T1 x, const string y) :mx(x), my(y) { cout << "部分具体化:构造函数 " << endl; };void show()const {cout << "部分具体化x=" << mx << ",y=" << my << endl;};
};int main() {//具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类AAaa(22, "光头强");aa.show();system("Pause");return 0;
}

类模板的继承

  1.  模板类继承普通类(常见)

  2. 普通类继承模板类的实例版本

  3. 普通类继承模板类(常见)

  4. 模板类继承模板类

  5. 模板类继承模板参数给出的基类(不能是模板类)

下面演示第一种:模板类继承普通类

#include 
using namespace std;class AA {  // 普通类AA
public:int m_a;AA(int a) :m_a(a) { cout << "调用AA构造函数" << endl; }void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }};template
class BB:public AA  // 模板类BB
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y,int a):AA(a),m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }};int main() {BBbb(22, "光头强", 6666);bb.func1();cout << "--------------------" << endl;bb.func2();system("Pause");return 0;
}

第三种情况:普通类继承模板类:

#include 
using namespace std;template
class BB  // 模板类BB
{
public:T1 m_x;T2 m_y;BB(const T1 x, const T2 y):m_x(x), m_y(y) { cout << "调用BB构造函数" << endl; }void func2() { cout << "调用func2函数,x+y=" << m_x <<",m_y=" << m_y << endl; }};template
class AA:public BB {  // 普通类AA
public:int m_a;AA(int a,const T1 x,const T2 y) :BB(x,y),m_a(a) { cout << "调用AA构造函数" << endl; }void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }};int main() {AAaa(1,22, "光头强");aa.func1();cout << "--------------------" << endl;aa.func2();system("Pause");return 0;
}

类模板的成员模板

#include 
using namespace std;template
class AA {
public:T1 m_x;T2 m_y;AA(const T1 x,const T2 y):m_x(x),m_y(y){}void show() { cout << "m_x=" << m_x << " m_y=" << m_y << endl; }template // 类模板class BB{public:T m_a;T1 m_b;BB(){}void show() { cout << "m_a=" << m_a << " m_b=" << m_b << endl; }};BBbb;  // bb就是类模板AA的一个成员//函数模板templatevoid showf(TF tt) { cout << "tt=" << tt << endl; }};int main() {AAa(22, "光头强");a.show();a.bb.m_a = "熊大";a.bb.show();a.showf("看我大卫天龙");system("pause");return 0;
}

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...