这是EasyC++系列的第42篇,来聊聊模板显式实例化。 实例化和具体化 关于函数模板,还有一个很重要的概念,就是实例化。...我们在编写代码时,如果只是编写了函数模板本身,编译器是不会为我们生成函数的定义的。当编译器使用模板为特定的类型生成函数定义时,就会得到一个模板的实例。...在早年的C++版本当中只支持隐式实例化,但现在C++允许显示实例化。也就意味着我们可以手动命令编译器创建特定的实例,比如Swap()。...显式具体化的含义是对于某特定类型不要使用原模板生成函数,而应专门使用指定的函数定义。而显式实例化是使用之前的模板函数的定义的,只不过是手动触发编译器创建函数实例而已。...对了,我们不能同时在一个文件中,使用同一种类型的显式实例化和显式具体化,这会引起报错。 我们如果死记显式实例化的声明,的确很容易和具体化混淆。
1.C++函数匹配顺序 C++语言引入模板机制后,函数调用的情形显的比C语言要复杂。当发生一次函数调用时,如果存在多个同名函数,则C++编译器将按照如下的顺序寻找对应的函数定义。...(1)寻找一个参数完全匹配的函数,如果找到了就调用它。 (2)寻找一个函数模板,并根据调用情况进行参数推演,如果推演成功则将其实例化,并调用相应的模板函数。...函数申明对函数模板实例化的屏蔽 如果使用了函数申明,可能会造成对函数模板实例化的屏蔽。考察如下程序。...这种现象,可以把它叫做函数申明对函数模板实例化的屏蔽。其本质是,在发生函数调用的时候,编译器总是优先调用普通函数而不是函数模板。要解决这个问题,可以采取以下三种办法。 (1)去掉函数申明。...(const T&);这样就会启用函数模板的实例化。
定义 函数模板不是一个实在的函数,编译器不能为其生成可执行代码。定义函数模板后只是一个对函数功能框架的描述,当它具体执行时,将根据传递的实际参数决定其功能。 这他妈的,god知道是什么东西啊!...Swap的类型,但是发现,我们传入的n,m都是int类型,所以自己用int来代替函数模板中的T 要实现函数模板的理解,我们还应该了解专业术语: 实例化:1 实例化 实例化有两种形式,分别为显式实例化和隐式实例化...模板并非函数定义,实例式函数定义。 1.1 显式实例化(explicit instantiation) 显式实例化意味着可以直接命令编译器创建特定的实例,有两种显式声明的方式。...显式具体化将不会使用Swap()模板来生成函数定义,而应使用专门为该特定类型显式定义的函数类型。...,如下,其中job为用户自定义类 template void Swap(job &a, job &b) template void Swap(job &a, job &b) 显式具体化在声明后
函数模板的匹配原则 函数模板的匹配原则是 C++ 中重载决议的核心规则之一,决定了编译器在多个候选函数(包括模板和非模板函数)中选择最合适版本的优先级顺序。...1、语法检查 两阶段名称查找(Two-Phase Lookup): 第1阶段:解析模板定义时检查非依赖名称(如全局函数、字面量类型)。...显式实例化声明 减少重复实例化:在头文件中声明 extern template,在某个.cpp文件中集中定义。...例如,在不同的命名空间中使用同一个模板函数,实例化时需要考虑命名空间的影响。 实现方式: 通过维护作用域栈和命名空间信息,在实例化时根据当前的作用域和命名空间来确定实例化上下文。...实现方式: 在符号表中查找是否存在针对当前类型的特化模板定义,如果存在,则进行合法性检查并使用该特化版本。 后端编译阶段 - 具体代码生成 工作原理: 根据重写后的模板代码生成具体的目标代码。
C++类模板实例化对象,向函数传参的方式一共有3种: 指定传入的类型:直接显示对象的数据类型; #include #include using namespace std...Demo d("孙悟空", 500000); print_demo(d); } int main(){ test(); return 0; } 参数模板化...:将对象中的参数变为模板进行传递; #include #include using namespace std; template d("唐僧", 5000); print_demo(d); } int main() { test(); return 0; } 整个类模板化...:将对象类型模板化进行传递。
模板是泛型编程的基础。 二.函数模板 --函数模板代表了一个函数家族。该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。...2.3 函数模板的实例化 用不同类型的参数使用函数模板时,称为函数模板的实例化。模板参数实例化分为:隐式类型实例化和显示实例化。...:在函数名后的中的指定模板参数的实际类型 #include using namespace std; template T Add(const T& left...,在调动时会优先调用非模板函数而不会从该模板产生出一个实例。...》 《吃透 C++ 类和对象(中):const 成员函数与取地址运算符重载解析》 《吃透 C++ 类和对象(下):从初始化列表到编译器优化,7 大核心考点让你彻底告别面试卡壳!》
然而,当函数分布在不同命名空间中时,重载的规则变得更为复杂 —— 命名空间的作用域规则、using声明 / 指示的引入机制,以及实参相关查找(ADL)会共同影响重载集的构成。...1.2 命名空间对候选函数的隔离 若函数定义在不同命名空间中,即使同名且参数列表相同,也不会自动形成重载 —— 它们属于不同的作用域,需通过using声明或指示引入后才可能参与重载。...引入后,该函数会与当前作用域的同名函数(参数列表不同)形成重载。...5.3 命名空间与模板特化的可见性 模板特化(Template Specialization)需在原模板的作用域内声明,否则无法被正确查找。若原模板在命名空间中,特化也需在同一命名空间中。...-x : x; } } int main() { std::cout 实例化原模板
当其它的要素都相等时,重载机制将优先选择调用非函数模板而不是函数模板【对于这个问题,个人觉得可能是基于如下的原因:进行重载将降低程序的效率,对非函数模板是如此,对于更为复杂的函数模板更是如此(至少还需进行一次实例化...那些无法跟非函数模板进行最佳匹配的,则调用函数模板的实例化对象,如第一和第二个函数调用。...中的参数用于指定函数模板中,传入的参数类型跟返回值类型,列表中参数的顺序对应于模板中声明的类型的顺序。这里的参数列表为空,但却告诉了编译器,这个函数只在函数模板中选择最佳匹配的函数调用。...同样的,max( 7, 42 ); 调用的是函数模板的一个实例化对象,这里指定了模板参数的类型,因此对于传入的值,程序会对其进行一个转换(从int转为double),然后比较大小。...【二】重载是个什么样的过程? 查找名称,从而形成一个初始化的重载集(合)。 如果有必要,会用各种方法对这个集合进行修改(例如,发生模板演绎的时候)。
) { ... } 2.3 函数模板的实例化 函数模板本身并不是函数,而是一个用于生成函数的蓝图。...函数模板重载是指定义多个同名的函数模板,它们的模板参数列表或函数参数列表不同。编译器在调用时需要同时考虑模板实例化和重载解析两个过程。...,构成重载 四、函数匹配与模板实例化 4.1 重载解析的三个步骤 当调用一个重载函数或函数模板时,编译器按以下步骤确定最佳匹配: 确定候选函数集:包括所有可见的同名函数和函数模板实例 确定可行函数...理解函数匹配规则和模板实例化过程是掌握这一技术的关键: 函数重载:通过参数列表的不同区分同名函数 函数模板:实现代码的泛型化,通过模板参数推导实例化 模板重载:多个同名模板通过参数列表区分 重载解析:编译器按优先级选择最佳匹配函数...特化与重载:特化不参与重载解析,而是替换已选择的模板实例 合理使用函数重载和模板重载,可以使代码更加简洁、灵活和可维护。
编写的函数模板可能无法处理某些类型显式具体化 方法:对于给定的函数名,可以有⾮模板函数、模板函数和显式具体化模板函数以及它们的重载版本。...显式实例化语法: templat void Swap(int ,int);在同一个文件中使用同一种类型的显式实例和显式具体化将出错。隐式实例化、显式实例化和显式具体化统称为具体化。...引⼊显式实例化后,必须使⽤新的语法——在声明中使⽤前缀 template和template ,以区分显式实例化和显式具体化。...这个过程称为重载解析(overloading resolution)。过程:创建候选函数列表。其中包含与被调⽤函数的名称相同的函数和模板函数。使⽤候选函数列表创建可⾏函数列表。...E's debts: template B 2400 1300 1800 ``` 重载解析将寻找最匹配的函数。
上篇我们介绍了java中的构造方法,了解了关键字this和super在继承中所起到的作用,this可以显式调用重载的构造方法,super可以显式的调用父类中的任意可见方法。...了解方法重载和重写的区别,知道了关键字final的作用,本篇将以一段代码介绍实例化对象时内存的状态。 如果你能看懂以下代码,那本篇你就不用浪费时间了。...所以程序开始做的第一件事情是:加载类,就是将类的信息加载到内存中,一个类的信息主要有: 静态变量 静态初始化代码块 静态方法 实例变量 实例初始化代码块 实例方法 对继承自父类的信息的引用 类的加载过程如下...执行new语句,发现Child类并未加载到方法区,于是加载Child类到方法区,然后根据方法区中的Child类的模板new出child类的实例对象,它具有模板中所有信息, ?...执行new操作,并调用child类的构造方法,转去调用Base类的构造方法,调用函数print,于是判断出此对象的实际类型是child,在child类中查找print找到并执行输出还未显式初始化的a=0
: 函数模板的签名包括模板参数,返回值,函数名,函数参数, cv-qualifier; 函数模板编译顺序大致:名称查找(可能涉及参数依赖查找)->实参推导->模板实参替换(实例化,可能涉及 SFINAE...)->函数重载决议->编译; 函数模板可以在实例化时候进行参数推导,必须知道每个模板的实参,但不必指定每个模板的实参。...这发生在尝试调用函数、取函数模板地址时,和某些其他语境中; 函数模板在进行实例化后会进行函数重载解析, 此时的函数签名不包括返回值(template argument deduction/substitution...); 函数模板实例化过程中,参数推导不匹配所有的模板或者同时存在多个模板实例满足,或者函数重载决议有歧义等,实例化失败; 为了编译函数模板调用,编译器必须在非模板重载、模板重载和模板重载的特化间决定一个无歧义最佳的模板...SFINAE -Substitution failure is not an error 要理解这句话的关键点是failure和error在模板实例化中意义,模板实例化时候,编译器会用模板实参或者通过模板实参推导出参数类型带入可能的模板集
类模板不会推断参数的类型 类模板的成员函数只有在使用时才会实例化 类模板与另一个模板直接最常见的友元是一对一的友元,首先模板需要声明所有需要用到的名字,然后在声明友元时标注出目标类的具体模板实参 类模板也可以一对多友元...,做法和默认函数实参类似但是写在模板参数列表里,也只能出现在最右侧 当需要在类外部定义类成员模板时,要注意此时需要两个template连用来说明标识符 extern显式实例化会实例化模板的所有成员,包括内联的成员函数...forward函数,能恢复被右值引用参数去除的右值引用属性 在没有歧义的情况下,永远会调用发生了最少改变,最精确匹配,最不需要调用自定义类型转换,最不需要调用模板的那个重载,即“更特例化” 可变参数模板就是一个能接受数目可变类型也可变的参数的类...,另一种用法是对包中的每个元素都自动调用一个指定的函数,并返回处理后的返回值 模板特例化的写法是将template尖括号中的需要特例化的内容删去,然后对下方用到的模板类型转为需要确定的类型。...即使我们需要特例化所有的类型参数也要保留一个空的尖括号做标记 完全的模板特例化的本质是模板的一个实例,而不是重载,因此特例化不会影响函数的匹配。
,它实例化之后变成一个模板函数,其作用如这个函数模板的注释所示,插入换行符并刷新输出流。...2.cout<< endl的介绍 endl是一个函数模板,再被使用时会实例化为模板函数。...查找ostream类的定义,发现其实是另一个类模板实例化之后生成的模板类,即: typedef basic_ostream > ostream; 所以,实际上应该在类模板...在头文件ostream中查找basic_ostream的定义,发现其中operator函数被重载了17次,其中的一种: typedef basic_ostream函数模板,或者说endl是一个经过隐式实例化之后的模板函数,我们把程序改造如下: #include using namespace std; int main
,它实例化之后变成一个模板函数,其作用如这个函数模板的注释所示,插入换行符并刷新输出流。...2.cout<<endl的介绍 endl是一个函数模板,再被使用时会实例化为模板函数。...查找ostream类的定义,发现其实是另一个类模板实例化之后生成的模板类,即: typedef basic_ostream > ostream; 所以,实际上应该在类模板...在头文件ostream中查找basic_ostream的定义,发现其中operator函数被重载了17次,其中的一种: typedef basic_ostream函数模板,或者说endl是一个经过隐式实例化之后的模板函数,我们把程序改造如下: #include using namespace std; int main
,一个实例化的类型总是包含模板参数的 与之前说过的一样,在模板类外定义成员函数时需要先指明模板实参列表的标签,然后说明成员所在的类且包含模板实参,然后用作用域运算符指出目标成员 与函数模板有些相通,类模板的成员函数只有在使用时才会实例化...为了解决这个问题,我们要进行显式实例化 通常的实例化做法是在所有需要得到模板声明的地方对模板的声明注明是extern的,这样编译器不会在这个模板实例化的时候生成代码而是去程序别处查找模板的实例 然后我们要保证这个...unique_ptr为了性能,将删除器的类型在模板参数中传入,编译时绑定,这样之后使用的时候可以直接调用实例化的删除器,但是无法在实例化后更改删除器了 16.2 模板实参推断 从函数实参来确定模板实参的过程称为模板实参推断...,在模板实参推断过程中,编译器用函数调用中的实参类型来查找哪些函数版本最为匹配 对于函数模板与普通非模板函数不太一样,编译器通常不对实参进行类型转换从而只有几个类型转换会应用在实参上,编译器偏向于生成新的模板实例来适配...,编译器也会从模板函数中实例化出可以调用的合适的函数 因此一般在编写重载函数的时候会编写多个比较特例的函数然后保留一个接受const T&的模板函数来兜底防止失去匹配 在定义任何函数前异地你更要记得声明所有重载的函数版本防止编译器忽略你想要的版本而实例化了另一个
添加特化声明与实现 特化标识:用 template 表明这是一个模板特化(空尖括号表示不再推导模板参数 ) 明确特化类型:在函数名后的尖括号里,写上要专门处理的特定类型(如:Date* 类型,就写...传统分离编译流程: 编译器独立处理每个.cpp文件,生成对应的.obj文件 链接器将所有.obj文件合并,解析未定义的符号(如:函数调用) 模板实例化机制: 模板代码(如:template 模板分离编译问题的核心就是:让编译器在实例化模板时能同时看到声明与定义。 将声明和定义写在同一个头文件中,从根源上避免分离编译带来的符号解析问题,是最简单直接且兼容性最好的方案。 1....将模板定义放在头文件中 原理:让编译器在使用模板的编译单元(如:main.cpp)时同时看到声明和定义,直接实例化代码。...使用显式实例化 原理:在模板定义文件中显式指定需要实例化的类型,强制编译器生成对应代码。
功能 function template 函式模板、函式范本 函数模板 functor 仿函式 仿函式、函子 game 游戏 游戏 generate 生成 generic 泛型、一般化的 一般化的...「东西」) instantiated 具现化、实体化(常应用於 template) 实例化 instantiation 具现体、具现化实体(常应用於 template) 实例 integer (integral...功能 function template 函式模板、函式范本 函数模板 functor 仿函式 仿函式、函子 game 游戏 游戏 generate 生成 generic 泛型、一般化的 一般化的...「东西」) instantiated 具现化、实体化(常应用於 template) 实例化 instantiation 具现体、具现化实体(常应用於 template) 实例 integer (integral...多载化、重载 重载 overloaded function 多载化函式 重载的函数 overloaded operator 多载化运算子 被重载的操作符 overloaded set 多载集合 重载集合
2.类模板的成员函数只有在调用的时候才会实例化。 2.3 部分使用类模板 1.类模板实例化时,模板实参只需要支持被实例化部分所有用到的操作。...9.2 模板和 inline 函数模板全特化后和普通函数相同,但函数模板一般定义在头文件中,为了避免在多个模块 include 时出现重复定义的错误,一般将全特化后的函数模板定义为 inline。...实例化:查找到最匹配的模板后,根据实参从模板创建出常规类或函数的过程。 特例化:对模板中的部分或全部参数进行特化,定义新模板的过程。...14.3 c++实例化模型 1.两阶段查找:编译器在模板解析阶段会检测不依赖于模板参数的非依懒型名称,在模板实例化阶段再检查依懒型名称。...普通函数和模板函数也可以同时重载,此时在匹配程度相同时,优先调用普通函数。