C++08函数模板

news2024/11/16 7:22:21

1.自动推导类型

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

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

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

#include <iostream>
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 <iostream>
using namespace std;

template<typename T1, typename T2>
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 <iostream>
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 <iostream>
using namespace std;

// 创建一个函数模板,交换两个变量的值
// 定义模板,这里anytype可以随便取名,但是需要注意和下面一致
// 函数模板用typename  类模板用 class
template <typename T>
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 <iostream>
using namespace std;

class Fruit {
public:
	// 构造函数
	template <typename T>
	Fruit(T a) {
		cout << "a=" << a << endl;
	}

	// 用到模板的地方在上面都要加这一句
	template <typename T1,typename T2>
	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 <iostream>
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<typename T>
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 <iostream>
#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 <iostream>
using namespace std;

void Swap(int a, int b);  // 普通函数

template<typename T>   // 函数模板
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 T>

class 类模板名

{

        类的定义

}

#include <iostream>
using namespace std;

template<class T1,class T2>
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() {
	AA<int, double>a;  // 用模板类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<int, double>*a=new AA<int, double>(1,2);  // 用模板类AA创建对象

	cout << "a.geta()=" << a->geta() << endl;
	cout << "a.getb()=" << a->geta() << endl;

	delete a;
	system("Pause");
	return 0;
}

类模板的具体化

#include <iostream>
using namespace std;

//类模板
template<class T1,class T2>
class AA {
	T1 mx;
	T2 my;

	AA(const T1 x, const T2 y) :mx(x), my(y) { cout << "类模板,构造函数" << endl; }
	void show()const;//类内声明,类外实现
};

// 成员函数类外实现
template<class T1,class T2>
void AA<T1, T2>::show()const {
	cout << "类模板:x=" << mx << ",y=" << my << endl;
};

//类模板完全具体化
template<>class AA<int, string> {
public:
	int mx;
	string my;

	AA(const int x, const string y) :mx(x), my(y) { cout << "完全具体化:构造函数" << endl; };
	void show()const;
};

void AA<int, string>::show()const {
	cout << "完全具体化x=" << mx << ",y=" << my << endl;
};

//类模板部分显示具体化
template<class T1>
class AA<T1, string> {  // 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() {
	//具体化程度高的类优先于具体化程度低的类,具体化的类优先于没有具体化的类
	AA<int, string>aa(22, "光头强");
	aa.show();
	system("Pause");
	return 0;
}

类模板的继承

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

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

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

  4. 模板类继承模板类

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

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

#include <iostream>
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 T1,class T2>
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() {

	BB<int, string>bb(22, "光头强", 6666);
	bb.func1();
	cout << "--------------------" << endl;
	bb.func2();
	system("Pause");
	return 0;
}

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

#include <iostream>
using namespace std;



template<class T1,class T2>
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 T1, class T2>
class AA:public BB<T1,T2> {  // 普通类AA
public:
	int m_a;
	AA(int a,const T1 x,const T2 y) :BB<T1,T2>(x,y),m_a(a) { cout << "调用AA构造函数" << endl; }
	void func1() { cout << "调用func1函数:m_a=" << m_a << endl; }

};

int main() {

	AA<int, string>aa(1,22, "光头强");
	aa.func1();
	cout << "--------------------" << endl;
	aa.func2();
	system("Pause");
	return 0;
}

类模板的成员模板

#include <iostream>
using namespace std;

template<class T1,class T2>
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 T> // 类模板
	class BB
	{
	public:
		T m_a;
		T1 m_b;
		BB(){}
		void show() { cout << "m_a=" << m_a << " m_b=" << m_b << endl; }
	};

	BB<string>bb;  // bb就是类模板AA的一个成员

	//函数模板
	template<typename TF>
	void showf(TF tt) { cout << "tt=" << tt << endl; }

};

int main() {
	AA<int, string>a(22, "光头强");
	a.show();
	a.bb.m_a = "熊大";
	a.bb.show();
	a.showf("看我大卫天龙");


	system("pause");
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56531.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpirngBoot<读完包你更上一层楼>

目录 一、SpringBoot概念 1.1 什么是SpringBoot 1.2 为什么要学习SpringBoot 1.3 SpringBoot的特点 1.4 总结 二、入门案例 2.1 创建工程 2.1.1 创建一个空工程 2.1.2 工程名为project_test&#xff1a; 2.1.3 设置jdk版本为1.8 2.1.4 新建一个module 2.1.5 填写项…

入职字节外包一个月,我离职了

有一种打工人的羡慕&#xff0c;叫做“大厂”。 真是年少不知大厂香&#xff0c;错把青春插稻秧。 但是&#xff0c;在深圳有一群比大厂员工更庞大的群体&#xff0c;他们顶着大厂的“名”&#xff0c;做着大厂的工作&#xff0c;还可以享受大厂的伙食&#xff0c;却没有大厂…

[附源码]计算机毕业设计springboot吾悦商城管理系统

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

老司机带带你,教你学会Java中又骚又暴力的“反射”技术

在Java中有这么一个很骚的技术&#xff0c;几乎贯穿了所有主流的框架&#xff0c;在所有主流框架的底层中你都可以看见它的身影&#xff0c;这个技术就是反射。关于反射&#xff0c;有很多小白会觉得很难&#xff0c;搞不清楚到底是怎么回事&#xff0c;也不知道该怎么用&#…

VS Code快速实现Git PR操作

注意&#xff1a;建议先学习git的基本操作。 安装插件 下图中红圈标记的插件都安装好。 Fork上游仓库 在网页上点击你想要fork的仓库&#xff0c;点击fork 然后该仓库就会fork到你的github账户下面&#xff0c;如下图。 现在可以在你账户下面的repo&#xff08;我们称为下…

[附源码]Python计算机毕业设计Django和vue的茶文化交流平台的设计与实现

项目运行 环境配置&#xff1a; Pychram社区版 python3.7.7 Mysql5.7 HBuilderXlist pipNavicat11Djangonodejs。 项目技术&#xff1a; django python Vue 等等组成&#xff0c;B/S模式 pychram管理等等。 环境需要 1.运行环境&#xff1a;最好是python3.7.7&#xff0c;…

Global Mapper 导出图层功能的妙用(重采样、设置文件类型、切片、按掩膜提取or裁剪……)

许多GIS软件都有导出的功能&#xff0c;但其中大部分的导出功能比较单一直接&#xff0c;仅仅是导出而已&#xff0c;或者最多可以改个导出的格式&#xff0c;改个坐标。但是Global Mapper 不一样&#xff0c;导出功能非常非常多&#xff0c;比如重采样&#xff08;可以设置重采…

Vue3框架的创建的两种种方案(第十二课)

1 VueCLi脚手架的安装 Home | Vue CLI (vuejs.org) 使用方法 | Yarn 中文文档 (bootcss.com) 3 Vite脚手架的安装 Vite | 下一代的前端工具链 4 使用的软件 Visual Studio Code webstorm64.exe IntelliJ IDEA 2022.2.3 HBuilder X 方案一 VueCLi脚手架的安装 1 创…

[附源码]计算机毕业设计在线招聘网站Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

MobileViT

还是vit系列啊 只不过这次是Apple团队出的轻量级、通用且移动友好的网络框架 论文地址&#xff1a;https://arxiv.org/pdf/2110.02178.pdf 轻量级卷积神经网络 (CNN) 是移动视觉任务的事实。他们的空间归纳偏差使他们能够在不同的视觉任务中以较少的参数学习表示。 轻量级卷积…

微服务自动化【集群搭建】

目录 搭建 etcd 集群 etcd构建自身高可用集群主要有三种形式: 1. 静态部署(前提) 2. 集群搭建 3. 集群测试 搭建 etcd 集群 etcd构建自身高可用集群主要有三种形式: 静态发现:预先已知etcd集群中有哪些节点&#xff0c; 在启动时通过--initial-cluster参数直接指定好etc…

[附源码]JAVA毕业设计互联网保险网站(系统+LW)

[附源码]JAVA毕业设计互联网保险网站&#xff08;系统LW&#xff09; 目运行 环境项配置&#xff1a; Jdk1.8 Tomcat8.5 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&a…

JavaWeb(一)

前言 首先深入了解之前&#xff0c;先回顾一些基础知识 C/S & B/S 就比如咱们日常生活中&#xff0c;咱们说的CF是cs游戏&#xff0c;这个cs是什么意思&#xff08;年幼的我也十分痴迷CF游戏&#xff0c;过去式了 hhh&#xff09;这里的cs可不是咱们说的csgo或者cs游戏。…

Vue 官方文档2.x教程学习笔记 1 基础 1.4 模板语法 1.4.1 插值

Vue 官方文档2.x教程学习笔记 文章目录Vue 官方文档2.x教程学习笔记1 基础1.4 模板语法1.4.1 插值1 基础 1.4 模板语法 【介绍】 Vue.js 使用了基于 HTML 的模板语法&#xff0c;允许开发者声明式地将 DOM 绑定至底层 Vue 实例的数据。 所有 Vue.js 的模板都是合法的 HTML&…

Flink SQL管理平台flink-streaming-platform-web安装搭建-整理

目录 步骤 安装 第二步 下载flink 第三步 安装flink-streaming-patform-web 第四步 配置flink web平台 第五步 运行demo 在Flink学习的入门阶段&#xff0c;非常重要的一个过程就是Flink环境搭建&#xff0c;这是认识FLInk框架的第一步&#xff0c;也是为后续的理论学习和…

全栈性能测试教程之性能测试理论(一) mockserver应用

1、mockServer 1.1什么是mockServer moco替代 Server服务 mocoServer即为测试替身的服务 主要针对于单元测试的应用&#xff0c;主要应用于解除单元测试之间的依赖 1.2mocoServer使用的场景 前端程序员 前端已经写好页面&#xff0c;但是后端的接口没有写好&#xff…

[Android]Mac电脑Android Studio使用真机调试运行

一、Mac电脑连接Android真机 我这里是一台中兴手机 1. 手机打开USB调试 打开“设置”找到“关于手机”进入&#xff0c;连续点击版本号&#xff0c;直到提示“您已经进入开发者模式”。回到“设置”找到“系统与更新”进入&#xff0c;再进入“开发者选项”&#xff0c;打开…

Vue笔记_03组件_mavonEditor组件(基于vue)

目录下载mavonEditor导入并注册mavonEditor组件[1] 全局注册[2]局部注册使用mavonEditor属性修改举例说明1-不展示预览分屏工具栏修改举例说明-根据配置显示工具栏编辑器插槽举例说明-自定义工具栏按钮函数监听下载mavonEditor 使用命令 npm install mavon-editor --s 进行下载…

Koa 6 响应(Response)

Koa Koa 本文仅用于学习记录&#xff0c;不存在任何商业用途&#xff0c;如侵删 6 响应(Response) 文章目录Koa6 响应(Response)6.1 APIStringBufferStreamObjectKoa Response 对象是在 node 的原生响应对象之上的抽象&#xff0c;提供了诸多对 HTTP 服务器开发有用的功能。 6…

Linux系统移植一:移植U-BOOT 添加自己的板子并编译(非petalinux版)

Linux系统移植流程 之前一直用官方给的Linux系统文件&#xff0c;没有自己系统地移植过&#xff0c;故整理一遍 不使用petalinux工具&#xff0c;尽管它提升了开发效率&#xff0c;但是不利于学习移植过程 嵌入式Linux系统移植主要由四大部分组成&#xff1a; 搭建交叉开发环…