首页 > 编程语言 >c++函数模板和运行机制

c++函数模板和运行机制

时间:2024-04-19 10:14:35浏览次数:24  
标签:函数 int c++ 类型 编译器 参数 运行机制 模板

C++_template

c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函数的功能。

  • c++提供两种模板机制:函数模板和类模板
  • 类属:类型参数化,又称参数模板

函数模板

函数模板是 C++ 中的一种特性,它允许你编写一个通用的函数,能够处理不同类型的数据,而不需要针对每种类型编写多个函数。通过函数模板,你可以编写一次代码,然后使用不同的数据类型来实例化该函数,从而生成针对不同数据类型的具体函数。

函数模板可以处理各种不同的数据类型,只要这些数据类型支持所执行的操作。例如,你可以使用函数模板来编写一个通用的排序函数,它可以对整数、浮点数、字符串等进行排序,而无需为每种类型编写一个特定的排序函数。

假设现在有几个类似函数:

void SwapInt(int& a, int& b) {
	int temp = a;
	a = b;
	b = temp;
}

void SwapChar(char& a, char& b) {
	char temp = a;
	a = b;
	b = temp;
}

如果要交换double,bool等其他类型时,需要重复写很多个功能相同的函数。写的函数越多,当交换逻辑发生变化的时候,所有的函数都需要修改,无形当中增加了代码的维护难度。

template<class T>

void Swap(T& a, T& b) {
	T temp = a;
	a = b;
	b = temp;
}
void test() {
	int a = 10;
	int b = 20;
	cout << "a:" << a << " b:" << b << endl;
	//1. 这里有个需要注意点,函数模板可以自动推导参数的类型
	Swap(a, b);
	cout << "a:" << a << " b:" << b << endl;
	cout << "-----------------\n";
	char c1 = 'a';
	char c2 = 'b';
	cout << "c1:" << c1 << " c2:" << c2 << endl;
	//2. 函数模板可以自动类型推导,那么也可以显式指定类型
	Swap<char>(c1, c2);
	cout << "c1:" << c1 << " c2:" << c2 << endl;
}

image-20240419092905080

普通函数和函数模板区别

  1. 定义
    • 普通函数:定义时指定了具体的参数类型和返回类型,如 int add(int a, int b)
    • 函数模板:定义时使用关键字 template 并在尖括号中声明模板参数,如 template <typename T> T add(T a, T b)
  2. 参数类型
    • 普通函数:参数类型是固定的,无法处理不同类型的参数。
    • 函数模板:参数类型可以是模板参数,因此可以处理不同类型的参数。
  3. 具体化
    • 普通函数:只有一份具体的实现,不支持根据参数类型动态生成多个版本。
    • 函数模板:可以根据不同的模板参数生成多个具体化的版本,以应对不同的参数类型。
  4. 类型推断
    • 普通函数:参数类型必须显式指定。
    • 函数模板:可以通过函数参数的类型自动推断模板参数的类型。
  5. 使用
    • 普通函数:直接调用,参数类型必须与函数声明中指定的类型相匹配。
    • 函数模板:使用时可以通过显式指定模板参数的方式实例化模板,也可以让编译器自动推断模板参数的类型。

函数模板和普通函数在一起调用规则

  1. c++编译器优先考虑普通函数
  2. 可以通过空模板实参列表的语法限定编译器只能通过模板匹配
  3. 函数模板可以像普通函数那样可以被重载
  4. 如果函数模板可以产生一个更好的匹配,那么选择模板
template<class T>
T MyPlus(T a, T b) {
	T ret = a + b;
	return ret;
}
//普通函数
int MyPlus(int a, int b) {
	int ret = a + b;
	return ret;
}
void test() {
	int a = 10;
	int b = 20;
	char c = 'a';
	char d = 'b';
	//如果函数模板和普通函数都能匹配,c++编译器优先考虑普通函数
	cout << MyPlus(a, b) << endl;
	//如果我必须要调用函数模板,那么怎么办?
	cout << MyPlus<>(a, b) << endl;
	//此时普通函数也可以匹配,因为普通函数可以自动类型转换
	//但是此时函数模板能够有更好的匹配
	//如果函数模板可以产生一个更好的匹配,那么选择模板
	cout << MyPlus(c, d);
}

image-20240419094504835

为什么函数模板可以和普通函数放在一起?c++编译器是如何实现函数模板机制的?

hello.cpp程序是高级c语言程序,这种程序易于被人读懂。为了在系统上运行hello.c程序,每一条c语句都必须转化为低级的机器指令。然后将这些机器指令打包成可执行目标文件格式,并以二进制形式存储于磁盘中。

预处理(Pre-processing) -> 编译(Compiling) ->汇编(Assembling) -> 链接(Linking)

image-20240419095156067

函数模板机制结论:

  • 编译器并不是把函数模板处理成能够处理任何类型的函数: 函数模板本身并不是完整的可执行代码,而是一种通用的模板。编译器在编译过程中不会将函数模板直接处理成能够处理任何类型的函数,而是根据模板定义和实际使用情况生成特定类型的函数代码。这意味着函数模板并不直接对应于实际可执行的函数代码,而是在使用时根据模板参数生成相应的函数代码。
  • 函数模板通过具体类型产生不同的函数: 当程序中使用函数模板并提供具体类型的参数时,编译器会根据模板定义生成针对这些具体类型的函数代码。这个过程称为模板实例化。换句话说,函数模板在编译过程中会根据模板参数的具体类型产生不同的函数实现,以适应不同类型的参数。
  • 编译器会对函数模板进行两次编译,在声明的地方对模板代码本身进行编译,在调用的地方对参数替换后的代码进行编译: 这是指编译器在处理函数模板时的两个重要阶段:模板声明和模板实例化。在模板声明阶段,编译器会对函数模板的语法进行检查,并确保模板定义的正确性。在模板实例化阶段,编译器会根据模板参数的具体类型,对模板代码进行替换并生成实际的函数代码。这两个阶段都是在编译过程中发生的,但它们的重点和操作对象略有不同。

标签:函数,int,c++,类型,编译器,参数,运行机制,模板
From: https://www.cnblogs.com/ivanlee717/p/18145185

相关文章

  • c++ double进行精度截取 (转)
    使用boost/multiprecision/cpp_dec_float.hpp #include<boost/multiprecision/cpp_dec_float.hpp>usingboost::multiprecision::number;usingboost::multiprecision::cpp_dec_float_50;intmain(){cpp_dec_float_50v1("5726.867366095");......
  • 【模板】容斥原理
    集合形式设\(S\)是一个有限集,\(A_1,A_2,\dots,A_n\)是\(S\)的\(n\)个子集,则:\(|S-\cup_{i=1}^{n}A_i|=\sum\limits_{i=0}^{n}(-1)^i\sum\limits_{1\lej_1\lej_2\le\dots\lej_i}|S\cap(\cap_{k=1}^iA_{j_k})|\)符号形式设\(S\)是一个有限集,\(a_1,a_2\dotsa_......
  • C++ 类方法解析:内外定义、参数、访问控制与静态方法详解
    C++类方法类方法,也称为成员函数,是属于类的函数。它们用于操作或查询类数据,并封装在类定义中。类方法可以分为两种类型:类内定义方法:直接在类定义内部声明和定义方法。类外定义方法:在类定义内部声明方法,并在类外部单独定义方法。类内定义方法在类定义内部可以直接声明和......
  • [10] UE C++ 拓展知识
    SaveGame//--USnakeSaveGame.hUCLASS()classSNAKE_APIUSnakeSaveGame:publicUSaveGame{GENERATED_BODY()public:UPROPERTY()int32GameScore;UPROPERTY()FStringName;UPROPERTY()TArray<int32>Numbers;FStringSlotName;......
  • Controller使用模板
    /**Copyright2013-2018theoriginalauthororauthors.**LicensedundertheApacheLicense,Version2.0(the"License");*youmaynotusethisfileexceptincompliancewiththeLicense.*YoumayobtainacopyoftheLicenseat**......
  • Qt 6.5.5 链接和QML与C++交互的若干问题
    需求描述QtQuick开发桌面组件,使用讯飞API(提供头文件、静态库、动态库),希望部署到Windows平台,在QtCreator开发。QML与C++交互主要参考:QML与CPP,https://blog.csdn.net/gongjianbo1992/article/details/87965925另有参考:信号与槽,https://blog.csdn.net/ifeng12358/article/detai......
  • 深入分析C++对象模型之移动构造函数
    接下来我将持续更新“深度解读《深度探索C++对象模型》”系列,敬请期待,欢迎关注!也可以关注公众号:iShare爱分享,自动获得推文和全部的文章列表。C++11新标准中最重要的特性之一就是引入了支持对象移动的能力,为了支持移动的操作,新标准引入了一种新的引用类型——右值引用,右值引用一......
  • C++ - 中必须使用初始化列表初始化的四种情况
    1.必须使用初始化列表初始化一个引用成员;classCBase{public:CBase(inta):m_a(a)//正确,m_a是一个变量的引用,必须通过初始化列表初始化{//m_a=a;//错误cout<<"m_a:"<<m_a<<endl;}public:int&m_a;}; 2.......
  • C++实现string存取二进制数据的方法
    这篇文章主要介绍了C++实现string存取二进制数据的方法,针对STL中string的用法进行了较为详细的分析,需要的朋友可以参考下 本文实例讲述了C++实现string存取二进制数据的方法,分享给大家供大家参考。具体方法分析如下:一般来说,STL的string很强大,用起来也感觉很舒服,这段时间在......
  • 【字符编码】c++编码格式及转换
    参考资料:字符编码笔记:ASCII,Unicode和UTF-8通俗易懂wstring和string的区别wstring和string是C++中的两种字符串类型,它们的主要区别在于字符编码和存储方式。字符编码:string使用单字节字符编码,通常使用ASCII编码或其扩展(如UTF-8)。wstring使用宽字符编码......