百度竞价收费标准/长沙官网seo推广

百度竞价收费标准,长沙官网seo推广,沈阳博士男科医院好吗,企业咨询是什么工作欢迎来到ZyyOvO的博客✨,一个关于探索技术的角落,记录学习的点滴📖,分享实用的技巧🛠️,偶尔还有一些奇思妙想💡 本文由ZyyOvO原创✍️,感谢支持❤️!请尊重原创&#x1…

欢迎来到ZyyOvO的博客✨,一个关于探索技术的角落,记录学习的点滴📖,分享实用的技巧🛠️,偶尔还有一些奇思妙想💡
本文由ZyyOvO原创✍️,感谢支持❤️!请尊重原创📩!欢迎评论区留言交流🌟
个人主页 👉 ZyyOvO
本文专栏➡️C++ 进阶之路

在这里插入图片描述

各位于晏,亦菲们请看

  • 引言
  • 函数模板的概念
  • 函数模板的匹配原则
  • 函数模板的底层原理
    • 模板的编译阶段
    • 模板实例化
    • 编译器与链接器的协作
  • 编译器的工作流程
    • 前端编译阶段
    • 模板实例化阶段
    • 后端编译阶段
  • 函数模板总结
  • 写在最后

引言

点击快速复习 👉:【C++ 函数重载】—— 现代编译技术下的多态表达与性能优化

上篇文章我们讲到C++的函数重载,包括函数重载的条件,原理以及一些易错事项,那么本文我们为大家介绍C++中泛型编程的主要方式——模板。

在 C++ 中,模板(Template)是一种强大的编程特性,它允许程序员编写与类型无关的代码,实现代码的复用和泛型编程。

在这里插入图片描述

如同模具一样,C++中的模板也是同样的道理!


函数模板的概念

模板是 C++泛型编程的基础,它提供了一种将类型参数化的机制。模板分为类模板和函数模板,通过模板,我们可以定义通用的类或函数,这些类或函数可以处理多种不同的数据类型,而不需要为每种数据类型都编写一套单独的代码。这样可以提高代码的复用性和可维护性。

函数模板定义了一系列具有相似功能但可以处理不同数据类型的函数。通过使用模板,你无需为每种数据类型都编写一个单独的函数,而是可以定义一个通用的函数,让编译器根据实际使用的参数类型自动生成相应的具体函数。

定义

  • 函数模板的定义通常包含模板声明函数定义两部分。模板声明使用template关键字,后跟一个或多个模板参数列表,函数定义则使用这些模板参数来实现通用的逻辑。

语法:

template <typename T,typename T2,...typename Tn>
返回类型 函数名(参数列表){// 函数体
}
  • template:这是定义模板的关键字,表明接下来要定义一个模板。
  • typename(也可以用 class):用于声明一个类型参数,它告诉编译器 T 是一个代表任意类型的占位符。
  • T:类型参数的名称,你可以根据需要自定义,但通常使用单个大写字母,如 T、U 等。
  • 返回类型:函数的返回类型,可以是模板参数 T 或其他类型。
  • 参数列表:函数的参数列表,可以包含模板参数 T。

示例:

template<typename T>
void Swap( T& left, T& right)
{T temp = left;left = right;right = temp;
}

使用

隐式实例化

  • 让编译器根据实参自动推演模板参数的实际类型

使用函数模板时,你可以像调用普通函数一样调用它,编译器会根据传递的实参类型自动推导模板参数的类型。

声明一个模板:

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;int intResult = Add(a1, a2);double doubleResult = Add(d1, d2);return 0;
}
  • Add(a1, a2);:调用 Add 函数模板,编译器会根据传入的参数 a1 和 a2 的类型(int)自动推导模板参数 T 为 int,然后实例化出一个处理 int 类型的 Add 函数。
  • Add(d1, d2);:同理,调用 Add 函数模板时,编译器根据 d1 和 d2 的类型(double)推导模板参数 T 为 double,并实例化出一个处理 double 类型的 Add 函数。

下面这条语句不能通过编译,因为在编译期间,当编译器看到该实例化时,需要推演其实参类型通过实参a1将T推演为int,通过实参d1将T推演为double类型,但模板参数列表中只有一个T,编译器无法确定此处到底该将T确定为int
或者 double类型而报错.

Add(a1, d1);

注意:在模板中,编译器一般不会进行类型转换操作,因为一旦转化出问题,编译器就需要背黑锅,对于语句Add(a1, d1);

此时有两种处理方式:

  1. 用户自己来强制转化
Add(a, (int)d);
  1. 使用显式实例化

显示实例化

模板的显示实例化(Explicit Instantiation)是一种手动告诉编译器生成特定模板实例代码的机制.当你有函数模板时,编译器通常会在代码中第一次使用到特定模板实例时才生成对应的代码,但有时候你可能希望提前显式地让编译器生成特定类型的模板实例,这就需要用到显式实例化。

还是之前那个例子:

template<class T>
T Add(const T& left, const T& right)
{return left + right;
}

使用显示实例化

int main(void)
{int a = 10;double b = 20.0;// 显式实例化Add<int>(a, b);return 0;
}
  • 在这个例子中,Add<int>(a, b);这行代码显式地告诉编译器生成 Add 函数模板针对 int 类型的实例代码。
  • 如果类型不匹配,编译器会尝试进行隐式类型转换,如果无法转换成功编译器将会报错。
  • 此时编译器会将double类型的b转换为int类型来完成函数调用!

函数模板的匹配原则

函数模板的匹配原则是 C++ 中重载决议的核心规则之一,决定了编译器在多个候选函数(包括模板和非模板函数)中选择最合适版本的优先级顺序。

非模板函数优先

  • 如果存在非模板函数与调用参数完全匹配(无需隐式转换),则优先选择非模板函数,而非实例化模板。
#include <iostream>
// 模板函数
template <typename T>
void print(T a) {std::cout << "Template: " << a << std::endl;
}// 非模板函数(参数类型为 int)
void print(int a) {std::cout << "Non-template: " << a << std::endl;
}int main() {print(42);    // 调用非模板函数(精确匹配)print(3.14);  // 调用模板函数(生成 print<double>)
}

输出:

Non-template: 42
Template: 3.14

更特化的的模板函数优先

  • 当多个模板都能匹配时,编译器选择参数范围更狭窄(更特化)的模板。
#include <iostream>// 通用模板
template <typename T>
void show(T a) {std::cout << "Generic: " << a << std::endl;
}// 更特化的模板(针对指针)
template <typename T>
void show(T* a) {std::cout << "Specialized (pointer): " << *a << std::endl;
}int main() {int x = 10;show(x);    // 调用通用模板(T=int)show(&x);   // 调用指针特化版本(T=int)
}
  • 通用模板 T 可以匹配任何类型。
  • 指针特化模板 T* 只能匹配指针类型,因此更特化。

输出:

Generic: 10
Specialized (pointer): 10

精确匹配优先于隐式转换

  • 如果模板生成的实例化版本与非模板函数相比,参数匹配更精确(无需转换),优先选择模板。
#include <iostream>// 模板函数
template <typename T>
void log(T a) {std::cout << "Template log: " << a << std::endl;
}// 非模板函数(参数类型为 double)
void log(double a) {std::cout << "Non-template log: " << a << std::endl;
}int main() {log(42);     // 调用模板生成的 log<int>(精确匹配)log(3.14);   // 调用非模板函数(精确匹配)
}
  • 模板实例化版本:完全匹配 int
  • 非模板函数:需要 int → double 隐式转换

输出:

Template log: 42
Non-template log: 3.14
  • 对于非模板函数和同名函数模板,如果其他条件都相同,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。如果模板可以产生一个具有更好匹配的函数,那么将选择模板。
// 专门处理int的加法函数
int Add(int left, int right)
{return left + right;}
// 通用加法函数
template<class T1, class T2>
T1 Add(T1 left, T2 right)
{return left + right;
}
void Test()
{Add(1, 2); // 与非函数模板类型完全匹配,不需要函数模板实例化Add(1, 2.0); // 模板函数可以生成更加匹配的版本,编译器根据实参生成更加匹配的Add函数
}

显式指定模板参数

  • 显式指定模板参数时,编译器直接实例化模板,不参与与非模板函数的优先级比较。
#include <iostream>template <typename T>
void report(T a) {std::cout << "Template report: " << a << std::endl;
}void report(double a) {std::cout << "Non-template report: " << a << std::endl;
}int main() {report(42);           // 调用模板生成的 report<int>report<double>(3.14); // 强制调用模板生成的 report<double>report(3.14);         // 调用非模板函数(精确匹配 double)
}

显式指定模板参数

  • 用户强制要求实例化 report<double>

跳过非模板函数检查

  • 显式指定模板参数时,编译器直接生成 report<double>,不再考虑非模板函数。

结果

  • 调用模板实例化的report<double>,而非 非模板函数 report(double a)

输出:

Template report: 42
Template report: 3.14
Non-template report: 3.14

优先级总结

#include <iostream>// 非模板函数
void test(int a) {std::cout << "Non-template: " << a << std::endl;
}// 通用模板
template <typename T>
void test(T a) {std::cout << "Generic template: " << a << std::endl;
}// 更特化的模板(针对 double)
template <>
void test(double a) {std::cout << "Specialized template: " << a << std::endl;
}int main() {test(42);     // 非模板函数(精确匹配)test(3.14);   // 更特化的模板(double 特化)test("Hi");   // 通用模板(T=const char*)
}
  • 非模板函数 > 特化模板 > 通用模板
  • 精确匹配(无需类型转换)优先于需要隐式转换的函数。
  • 显式指定模板参数时,直接实例化模板(跳过非模板函数)。

输出:

Non-template: 42
Specialized template: 3.14
Generic template: Hi
开始
收集所有候选函数
当前作用域的所有同名函数
通过ADL查找的关联函数
模板参数推导
推导模板参数类型
是否所有参数推导一致?
推导成功,生成实例
推导失败,丢弃模板
生成可行候选列表
重载解析
参数匹配等级排序
精确匹配 > 提升转换 > 标准转换 > 用户定义转换
是否存在非模板函数?
优先选择非模板函数
选择最特化的模板
通过偏序规则比较模板
检查唯一性
是否唯一最佳匹配?
编译通过
报错: ambiguous call

函数模板的底层原理

模板的编译阶段

- 抽象语法树(AST)存储:

编译器将模板的语法结构(如函数参数、返回类型、操作逻辑)转换为AST保存,但不生成任何机器码。

template<typename T>
T max(T a, T b) { return (a > b) ? a : b; } 
// 仅保存AST,无代码生成

实例化触发

  • 隐式实例化:当代码中首次使用模板时触发。
int main() {max(3, 5);     // 触发 max<int> 的实例化max(3.0, 5.0); // 触发 max<double> 的实例化
}

实例化位置:编译器在调用点的作用域内生成实例化代码,通常位于当前编译单元(.cpp文件)内。

  • 显式实例化控制

手动指定实例化:通过 template 关键字强制生成特定类型的实例。

template int max<int>(int, int); // 显式实例化 int 版本

类型推导的底层逻辑

推导规则

  • 按值传递:编译器执行类型退化(Decay),移除引用、const/volatile 修饰符,数组退化为指针。
template<typename T>
void f(T t) {}const int a = 10;
int arr[3] = {1, 2, 3};
f(a);    // T = int(移除const)
f(arr);  // T = int*(数组退化为指针)
  • 按引用传递:保留原始类型信息。
template<typename T>
void f(T& t) {}const int a = 10;
f(a); // T = const int(保留const)
  • 万能引用(Forwarding Reference

引用折叠规则:T&& 根据实参的左右值推导不同结果。

引用折叠规则:
T& & → T&
T&& & → T&
T& && → T&
T&& && → T&&
template<typename T>
void f(T&& t) {}int a = 10;
f(a);   // T = int&(左值 → T& && → T&)
f(10);  // T = int(右值 → T&&)

模板实例化

1、语法检查

  • 两阶段名称查找(Two-Phase Lookup):

第1阶段:解析模板定义时检查非依赖名称(如全局函数、字面量类型)。

template<typename T>
void func(T t) {int x = 10;          // 非依赖名称,立即检查std::cout << x;      // 依赖名称,延迟检查
}

第2阶段:实例化时检查依赖名称(如 T::member、模板参数相关的表达式)。

2、生成机器码

  • 符号生成与名称修饰:为每个实例生成唯一的符号名。
GCC/Clang:_Z3maxIiET_S0_S0_(max<int>)。MSVC:??$max@H@@YAHHH@Z(max<int>)。

符号组成:

  • 函数名、模板参数、命名空间、参数类型等编码。

示例:void ns::foo<int, double>(int*) 可能被编码为:

GCC:_ZN2ns3fooIiJdEEEvPi
MSVC:??$foo@H$0A@@ns@@YAXPAH@Z

反编译工具:

  • GCC:c++filt _ZN2ns3fooIiJdEEEvPi → ns::foo<int, double>(int*)
  • MSVC:undname.exe 工具可解析修饰名。

3、 实例化重复与优化

  • 代码膨胀示例:
max(1, 2);       // 生成 int 版本
max(1L, 2L);     // 生成 long 版本
max(1.0f, 2.0f); // 生成 float 版本

每个实例独立生成代码,导致二进制文件增大。

  • 显式实例化优化:
// 在某个.cpp文件中集中实例化
template int max<int>(int, int);
template double max<double>(double, double);

模板特化的底层实现

  • 全特化(Full Specialization) 直接覆盖通用模板:生成特定类型的独立实现。
template<>
int max<int>(int a, int b) {// 定制化的int版本实现return (a > b) ? a : b;
}

编译器直接使用全特化版本,跳过通用模板逻辑。

  • 偏特化模拟(通过重载) 函数模板不支持偏特化,但可通过重载实现类似效果。
template<typename T> void process(T) {}      // 通用版本
template<typename T> void process(T*) {}     // 指针特化版本
template<typename T> void process(T[], int size) {} // 数组特化版本

SFINAE的底层机制

  • 替换失败:

在推导阶段,若替换模板参数导致非法表达式或类型,候选被静默排除。

示例:

template<typename T>
auto f(T t) -> decltype(t.size()) { ... } // 仅当 T 有 size() 时有效

编译器行为:

  • 尝试所有候选函数,排除无效替换的模板,保留有效候选参与重载。

编译器与链接器的协作

实例化重复问题

  • 多个编译单元实例化相同模板:每个.cpp文件独立生成 max<int>,导致重复代码。
  • 链接器合并:最终链接时保留一份 max<int> 的副本,其余被丢弃。

显式实例化声明

  • 减少重复实例化:在头文件中声明 extern template,在某个.cpp文件中集中定义。
// header.h
extern template int max<int>(int, int); // 声明不实例化
// source.cpp
template int max<int>(int, int);        // 实际实例化

底层示例:从代码到汇编

  • 代码示例:
template<typename T>
T add(T a, T b) { return a + b; }int main() {add(1, 2);     // 实例化 add<int>add(3.0, 4.0); // 实例化 add<double>
}
  • GCC生成的汇编代码(简化版)
; add<int> 的实例化
_Z3addIiET_S0_S0_:lea    eax, [rdi + rsi]  ; 整数加法(寄存器操作)ret; add<double> 的实例化
_Z3addIdET_S0_S0_:addsd  xmm0, xmm1        ; 浮点数加法(SSE指令)retmain:mov    edi, 1            ; 传递参数1到edi(int调用约定)mov    esi, 2            ; 传递参数2到esicall   _Z3addIiET_S0_S0_ ; 调用 add<int>movsd  xmm0, [rip + .LC0] ; 加载3.0到xmm0movsd  xmm1, [rip + .LC1] ; 加载4.0到xmm1call   _Z3addIdET_S0_S0_ ; 调用 add<double>xor    eax, eax          ; 返回0ret
开始
词法分析
语法分析
语义分析 - 模板定义检查
模板定义符号表构建
模板实例化请求
是否为显式实例化?
显式实例化处理
隐式实例化处理
实例化上下文确定
模板参数推导
模板参数替换
重写模板代码
是否有模板特化?
查找特化版本
使用通用模板
特化版本合法性检查
生成具体代码
中间代码生成
代码优化 - 局部优化
代码优化 - 全局优化
目标代码生成
符号解析
链接
结束

编译器的工作流程

  • 编译器的整体结构

编译器通常可以分为前端(Front - End)、中端(Middle - End)和后端(Back - End)三个主要部分:

  • 前端:负责处理与源语言相关的分析工作,包括词法分析、语法分析、语义分析等,将源代码转换为一种中间表示形式(IR)。
  • 中端:对中间表示形式进行优化,提高代码的性能和效率,不依赖于具体的源语言和目标机器。
  • 后端:将优化后的中间表示形式转换为目标机器的机器语言代码,处理与目标机器相关的问题,如寄存器分配、指令选择等。

对于函数模板,编译器会经过如下几个阶段处理:

前端编译阶段

  • 词法分析(Lexical Analysis
  • 工作原理:

编译器的词法分析器会按字符逐个读取源代码,将其拆分成一个个词法单元(Token)。例如,对于代码

 template <typename T> T add(T a, T b) { return a + b; }

词法分析器会识别出 template、<、typename、T等词法单元。

  • 实现方式:

通常使用有限状态自动机(Finite State Automaton, FSA)来实现。编译器会预先定义好各种词法单元的模式,当读取字符时,根据当前状态和输入字符进行状态转移,最终识别出对应的词法单元。例如,使用正则表达式来描述标识符、关键字等的模式,再将正则表达式转换为有限状态自动机进行匹配。


  • 语法分析(Syntax Analysis
  • 工作原理:

语法分析器根据词法分析器输出的词法单元序列,依据 C++ 的语法规则构建抽象语法树(Abstract Syntax Tree, AST)。AST 是一种树形结构,它以一种更结构化的方式表示源代码的语法结构。例如,对于上述 add 函数模板,AST 会包含模板声明、函数定义、参数列表、函数体等节点。

  • 实现方式:

常见的实现方法有递归下降分析法、算符优先分析法和 LR 分析法等。递归下降分析法是一种自顶向下的分析方法,它为每个非终结符编写一个递归函数,通过递归调用这些函数来构建 AST。例如,对于函数定义,会有一个函数来处理函数头,另一个函数来处理函数体。


  • 语义分析 - 模板定义检查
  • 工作原理:

语义分析器对 AST 进行检查,确保模板定义符合 C++ 的语义规则。例如,检查模板参数是否合法、模板函数体中的语句是否符合语法和语义要求等。对于 会检查 T 是否为合法的模板参数类型。

template <typename T> T add(T a, T b)
  • 实现方式:

通过遍历 AST,对每个节点进行语义检查。编译器会维护一些符号表和类型系统,用于记录和检查标识符的作用域、类型信息等。例如,当遇到一个变量时,会在符号表中查找其定义,并检查其类型是否与使用处匹配。


  • 模板定义符号表构建
  • 工作原理:

符号表是编译器用于记录标识符信息的数据结构。在模板定义阶段,编译器会为模板及其相关的标识符(如模板参数、函数名等)建立符号表项。例如,对于 add 函数模板,会在符号表中记录模板名 add、模板参数 T 以及它们的作用域等信息。

  • 实现方式:

通常使用哈希表或树形结构来实现符号表。当遇到一个新的标识符时,会在符号表中插入一个新的表项;当使用一个标识符时,会在符号表中查找对应的表项。


模板实例化阶段

- 模板实例化请求

  • 工作原理

:当代码中使用模板函数并指定具体类型时,会触发模板实例化请求。
例如:

int result = add<int>(1, 2);

会触发 add 函数模板针对 int 类型的实例化请求。

  • 实现方式:

编译器在编译过程中遇到模板函数调用时,会记录调用的位置和提供的模板参数类型,然后发起实例化请求。


  • 显式与隐式实例化判断
  • 工作原理:

编译器会根据代码中是否使用 template 关键字明确指定实例化来判断是显式实例化还是隐式实例化
例如:

template int add<int>(int, int); 

是显式实例化

add<int>(1, 2); 

是隐式实例化。

  • 实现方式:

在处理模板实例化请求时,检查代码中是否存在显式实例化的语法结构。


  • 实例化上下文确定
  • 工作原理:

确定实例化所需的环境和信息,包括命名空间、作用域等。例如,在不同的命名空间中使用同一个模板函数,实例化时需要考虑命名空间的影响。

  • 实现方式:

通过维护作用域栈和命名空间信息,在实例化时根据当前的作用域和命名空间来确定实例化上下文。


- 模板参数推导

  • 工作原理:

当调用模板函数时没有显式指定模板参数类型,编译器会根据调用时提供的实参类型推导出模板参数的具体类型。例如,add(1, 2); 编译器会根据实参 1 和 2 的类型 int 推导出模板参数 T 为 int。

  • 实现方式:

编译器会根据实参的类型和模板参数的匹配规则进行推导。匹配规则包括类型转换、引用折叠等。例如,如果实参是 const int 类型,而模板参数是 T,则会推导出 T 为 int。


- 模板参数替换

  • 工作原理:

将模板代码中的模板参数替换为具体类型。例如,对于 add 函数模板,当 T 被推导为 int 后,会将函数体中的 T 都替换为 int。

  • 实现方式:

通过遍历 AST,将所有与模板参数相关的节点替换为具体类型的节点。


- 重写模板代码

  • 工作原理:

根据替换后的类型,对模板代码进行重写,生成具体的函数代码。例如,将 add 函数模板重写为

 int add(int a, int b) { return a + b; }

实现方式:在 AST 上进行修改和生成新的代码节点,然后将修改后的 AST 转换为具体的源代码。


- 模板特化检查

  • 工作原理:

查看是否存在针对当前类型的特化版本。如果有特化版本,则使用特化版本;否则,使用通用模板。例如,对于 add 函数模板,如果存在针对 double 类型的特化版本,当调用 add<double>(1.0, 2.0) 时,会使用特化版本。

  • 实现方式:

在符号表中查找是否存在针对当前类型的特化模板定义,如果存在,则进行合法性检查并使用该特化版本。


后端编译阶段

- 具体代码生成

  • 工作原理:

根据重写后的模板代码生成具体的目标代码。编译器会将抽象的代码结构转换为具体的机器指令。例如,将 int add(int a, int b) { return a + b; } 转换为对应的汇编指令。

  • 实现方式:

使用代码生成器,根据目标机器的指令集和架构,将 AST 或中间表示转换为汇编代码。


- 中间代码生成

  • 工作原理:

将具体代码转换为中间表示形式(IR),便于后续优化。IR 是一种独立于目标机器的代码表示,具有更高的抽象层次。例如,将汇编代码转换为 LLVM IR

  • 实现方式:

通过对 AST 进行分析和转换,生成中间代码。中间代码通常具有更简单的结构和更统一的表示,便于进行各种优化操作。


- 代码优化

  • 工作原理:

对中间代码进行优化,提高代码的性能。优化包括局部优化和全局优化。局部优化主要针对单个函数或代码块内的代码进行优化,如常量折叠、死代码消除等;全局优化则考虑整个程序的上下文进行优化,如函数内联、循环展开等。

  • 实现方式:

使用各种优化算法和技术,如数据流分析、控制流分析等。例如,常量折叠是通过在编译时计算常量表达式的值,将表达式替换为计算结果;函数内联是将函数调用替换为函数体的代码。


- 目标代码生成

  • 工作原理:

将优化后的中间代码转换为目标机器的汇编代码。编译器会根据目标机器的指令集和架构,将中间代码中的操作转换为具体的机器指令

  • 实现方式:

使用目标代码生成器,根据中间代码和目标机器的信息生成汇编代码。


- 符号解析

  • 工作原理:

解析代码中的符号引用,确定符号的实际地址。在编译过程中,不同的源文件可能会引用相同的符号,符号解析的目的是将这些引用与实际的定义关联起来。例如,在一个源文件中调用另一个源文件中定义的函数,需要通过符号解析确定函数的实际地址。

  • 实现方式:

链接器会维护一个符号表,记录所有符号的定义和引用信息。在链接过程中,会根据符号表中的信息将符号引用与实际的定义进行匹配。


- 链接

  • 工作原理:

将多个目标文件链接成一个可执行文件。不同的源文件会被编译成不同的目标文件,链接器会将这些目标文件合并,并处理符号引用和重定位等问题。

  • 实现方式:

链接器会读取所有的目标文件和库文件,将它们的代码和数据段合并,处理符号引用和重定位信息,最终生成一个可执行文件。


函数模板总结

延迟编译与模板存储

  • 蓝图存储:模板定义时,编译器仅保存其语法结构(如AST),不生成机器码。
  • 触发实例化:首次调用时(如 max(3,5))才根据具体类型生成实际函数。

类型推导规则

  • 按值传递:退化类型(移除引用、const,数组/函数转指针)。
template<typename T> void f(T t);
f("Hello"); // T推导为 `const char*`(数组退化为指针)
  • 按引用传递:保留原始类型修饰符。
template<typename T> void f(T& t);
const int a = 10;
f(a); // T推导为 `const int`
  • 万能引用(T&&):根据实参左右值推导不同引用类型(引用折叠规则)。

实例化过程

  • 类型推导:确定模板参数 T。
  • 语法检查:验证 T 是否支持模板内所有操作(如 operator+)。
  • 生成机器码:将模板中的 T 替换为具体类型,生成独立函数。
  • 名称修饰:生成唯一符号名(如 Z3maxIiET_S0_S0 表示 max)。

符号管理与链接优化

  • 代码膨胀:每个类型生成独立实例(如 max 和 max)。
  • 显式实例化:通过 template int max(int, int); 集中生成代码,减少重复。
  • 链接器合并:多个编译单元中的相同实例在链接时仅保留一份。

模板特化与优先级

  • 全特化:直接覆盖通用模板,生成特定类型优化版本。
template<> int max<int>(int a, int b) { ... }
  • 偏特化模拟:通过重载实现(如针对指针或容器的特化版本)。

核心代价与优化策略

问题优化手段
代码膨胀显式实例化、类型擦除(如 std::function)
编译时间增长前置声明、extern template 声明
二义性错误明确模板参数、避免重载冲突

写在最后

本文到这里就结束了,有关C++更深入的讲解,如类模板,继承和多态,C++11新语法新特性等高级话题,后面会发布专门的文章为大家讲解。感谢您的观看!

如果你觉得这篇文章对你有所帮助,请为我的博客 点赞👍收藏⭐️ 评论💬或 分享🔗 支持一下!你的每一个支持都是我继续创作的动力✨!🙏
如果你有任何问题或想法,也欢迎 留言💬 交流,一起进步📚!❤️ 感谢你的阅读和支持🌟!🎉
祝各位大佬吃得饱🍖,睡得好🛌,日有所得📈,逐梦扬帆⛵!

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

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

相关文章

Redis 数据持久化之RDB

Redis数据持久化策略 持久化策略之RDB RDB:在指定的时间间隔&#xff0c;执行数据集的时间点快照。 实现类似照片记录效果的方式&#xff0c;就是把某一时刻的数据和状态以文件的形式写到磁盘上&#xff0c;也就是读快照。这样一来即使故障宕机&#xff0c;快照文件也不会丢失&…

数据分析与AI丨AI Fabric:数据和人工智能架构的未来

AI Fabric 架构是模块化、可扩展且面向未来的&#xff0c;是现代商业环境中企业实现卓越的关键。 在当今商业环境中&#xff0c;数据分析和人工智能领域发展可谓日新月异。几乎每天都有新兴技术诞生&#xff0c;新的应用场景不断涌现&#xff0c;前沿探索持续拓展。可遗憾的是&…

MyBatis - XML 操作动态 SQL

目录 1. 前言 2. 动态插入 2.1 if 标签 2.2 trim 标签 2.2.1 注解完成动态 SQL 3. 动态查询 3.1 添加 1 1 3.2 where 标签 4. 动态更新 4.1 set 标签 5. foreach 标签 6. sql 标签 & include 标签 1. 前言 之前博文所讲的 MyBatis SQL 操作, 都必须按照注解或…

【从零开始学习计算机科学】编译原理(七)运行时刻环境

【从零开始学习计算机科学】编译原理(七)运行时刻环境 运行时刻环境存储组织空间的栈式分配活动树活动记录和控制栈简单栈式存贮分配C语言的过程调用和过程返回时的存贮管理堆式存储分配堆式存储分配的功能垃圾回收基于跟踪的垃圾回收短停顿垃圾回收运行时刻环境 存储组织 …

2025-03-08 学习记录--C/C++-PTA 习题10-1 判断满足条件的三位数

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 裁判测试程序样例&#xff1a; #include <stdio.h> #include <math.h>int search( int n );int…

【ArcGIS】地理坐标系

文章目录 一、坐标系理论体系深度解析1.1 地球形态的数学表达演进史1.1.1 地球曲率的认知变化1.1.2 参考椭球体参数对比表 1.2 地理坐标系的三维密码1.2.1 经纬度的本质1.2.2 大地基准面&#xff08;Datum&#xff09;的奥秘 1.3 投影坐标系&#xff1a;平面世界的诞生1.3.1 投…

化工厂防爆气象站:为石油化工、天然气等领域提供安全保障

【TH-FB02】在石油化工、天然气等高危行业中&#xff0c;安全生产是至关重要的。这些行业常常面临着易燃易爆、有毒有害等潜在风险&#xff0c;因此&#xff0c;对气象条件的监测和预警显得尤为重要。化工厂防爆气象站作为一种专门设计用于这些特殊环境的气象监测设备&#xff…

《MySQL数据库从零搭建到高效管理|库的基本操作》

目录 一、数据库的操作 1.1 展示数据库 1.2 创建数据库 1.3 使用数据库 1.4 查看当前数据库 1.5 删除数据库 1.6 小结 二、常用数据类型 2.1 数值类型 2.2 字符串类型 2.3 日期类型 一、数据库的操作 打开MySQL命令行客户端&#xff0c;安装完MySQL后会有两个客户端…

计算机考研C语言

C语言程序设计从入门到精通【2025完整版】考研复试 嵌入式 计算机二级 软考 专升本也适用_哔哩哔哩_bilibili 1、第一个C程序 helloC #include <stdio.h>int main(){printf("hehe");return 0;}每个C语言程序不管有多少行代码&#xff0c;都是从main函数开始执…

力扣hot100二刷——链表

第二次刷题不在idea写代码&#xff0c;而是直接在leetcode网站上写&#xff0c;“逼”自己掌握常用的函数。 标志掌握程度解释办法⭐Fully 完全掌握看到题目就有思路&#xff0c;编程也很流利⭐⭐Basically 基本掌握需要稍作思考&#xff0c;或者看到提示方法后能解答⭐⭐⭐Sl…

Word 小黑第2套

对应大猫42 Word1 从文件中导入新样式 样式组 -管理样式 -导入导出 -关闭Normal文件 -打开文件 -修改文件 -选中所需 -复制 调整字符宽度 调整字符间距 -字体组 加宽 适当修改磅值 文字效果通过文字组修改 另起一页&#xff0c;分隔符&#xff08;布局 -分隔符 -分节符 -下一…

【RabbitMQ】Spring Boot 结合 RabbitMQ 完成应用间的通信

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【中间件】企业级中间件剖析 Spring 框架与 RabbitMQ 的整合主要通过 Spring AMQP&#xff08;Advanced Message Queuing Protocol&#xff09;模块实现&#xff0c;提供了便捷的消息队列开发能力。 引…

UVC摄像头命令推流,推到rv1126里面去

ffmpeg命令查询UVC设备 .\ffmpeg.exe -list_devices true -f dshow -i dummy 上图是查询UVC设备的效果图&#xff0c;画红框的部分是UVC设备的设备名称"USB2.0 PC CAMERA"和设备号 "device_pnp_\\?\usb#vid_1908&pid_2310&mi_00#8&39abfe5&0&a…

Linux中的基本指令(上)

目录 ls指令 判断linux中文件 pwd指令 认识路径 ​编辑 绝对路径/相对路径 cd指令 简要理解用户 理解家目录 echo指令和printf指令 touch指令 mkdir指令 cat指令 tree指令 rmdir指令和rm指令 man指令 cp指令 which指令 alias 指令 date指令 cal指令 理解…

Qt 数据库操作(Sqlite)

数据库简介 关于数据库的基础知识这里就不做介绍了&#xff0c;相关博客可以查看&#xff1a; SQL基础知识 数据库学霸笔记 上面博客都写的比较详细&#xff0c;本文主要介绍如何使用Qt进行数据库相关操作&#xff0c;数据库分为关系型数据库和非关系型数据&#xff0c;关系…

网络安全 api 网络安全 ast技术

随着应用或者API被攻击利用已经越来越多&#xff0c;虽然来自开源组件的漏洞加剧了这一现象的发生&#xff0c;但是&#xff0c;其实主要还是在于应用程序或者API本身没有做好防范&#xff0c;根源在于源代码本身的质量没有严格把控。AST是指Application Security Testing&…

Mac 配置 Maven JDK

不使用 Homebrew&#xff0c;创建指定版本 JDK 1、官网下载指定版本并安装……省略 2、vi &#xff5e;/.zshrc 同时要检查 bash_profile 是否存在。 if [ -f ~/.bash_profile ] ; thensource ~/.bash_profile fiJAVA_HOME_11/Library/Java/JavaVirtualMachines/jdk-11.0.1…

【病毒分析】熊猫烧香病毒分析及其查杀修复

目录 前言 一、样本概况 1.1 样本信息 1.2 测试环境及工具 1.3 分析目标 二、具体行为分析 2.1 主要行为 2.1.1 恶意程序对用户造成的危害 2.2 恶意代码分析 2.2.1 加固后的恶意代码树结构图(是否有加固) 2.2.2 恶意程序的代码分析片段 三、解决方案(或总结) 3.1 …

sqli-lab靶场学习(八)——Less26-28

前言 25关已经出现了初步的一些关键字过滤&#xff0c;通过双写可以绕过。后面的关卡&#xff0c;我们会遇到更多关键字过滤&#xff0c;需要各种技巧绕过。 Less26 第26关写了会过滤空格和注释符。有很多的答案&#xff0c;会用%a0替代空格&#xff0c;但据说这是sqli-labs部…

python:VOC格式数据集转换为YOLO数据集格式

作者&#xff1a;CSDN _养乐多_ 本文将介绍如何将目标检测中常用的VOC格式数据集转换为YOLO数据集&#xff0c;并进行数据集比例划分&#xff0c;从而方便的进行YOLO目标检测。 如果不想分两步&#xff0c;可以直接看第三节代码。 文章目录 一、将VOC格式数据集转换为YOLO格…