# 纲要 > 主干纲要、Hint/线索/路标 - **别名模版** - **函数模版** - **类模版** - **成员模版** %% # Q&A #### 已明确 #### 待明确 > 当下仍存有的疑惑 **❓<font color="#c0504d"> 有什么问题?</font>** %% <br> # 别名模版 Alias Templates 通过 `using` 声明为一个 "**==模版化类型==**" 指定别名的方式,称为 "**别名模版**"。 ```cpp template_alias.cpp /* 模版别名 * 可使用`using`来声明一个"模版化类型", 称之为"别名模版". * 由于模版不是"类型type", 因此不能使用`typedef`来声明模版别名. */ template <typename T> using Vec = std::vector<T>; template <typename T> using twin = pair<T, T>; template <typename T> using pairNo = pair<T, unsigned>; int main() { Vec<int> intVector; // 等价于`std::vector<int> intVector;` twin<int> obj1_1(1, 2); twin<char> obj1_2('A', 'B'); twin<double> obj1_3(3.14, 2.71); pairNo<int> obj2_1(3, 4); pairNo<char> obj2_2('C', 5); pairNo<double> obj2_3(2.718, 3); } ``` --- > [!caution] `typedef` 不能用于模版别名,因此 `C++98`中,要实现上述功能,需要采用 "将 `typedef` 嵌套进模版化的 `struct`" 来实现 "别名模版" 这一功能 > > 参见下例[^1]。 > ```cpp // 使用typedef来模拟 "别名模版" 的功能: template <typename T> struct Vec { typedef std::vector<T> type; } Vec<int>::type intVector; // 等价于`std::vector<int> intVector`; // 同时, `Vec<>::type` 作为依赖类型(依赖于模版参数)时, 还需要通过关键字`typename`显式指出 template<typename T> class Widget { private: typename Vec<T>::type member; // 注意, `typename` 指示 `Vec<T>::type` 是一个类型名 } ``` <br><br> # 函数模版 Function Templates 函数模板是**使用模板参数**来泛型定义函数的方式,支持同一函数实现对不同的数据类型进行操作。 > [!NOTE] "函数模版" 与 "模版函数" 的区别 > > - **函数模版**(Funtion Template):是"模版",是基于模版参数来泛型定义的一个函数体 > > - **模版函数**(Function Generated from a Template):是 "函数模版" 经实例化得到的**具体函数**。 > 函数模版可以声明为 `inline` 或 `constexpr` 的,这两关键字放在**模版参数列表之后,函数返回类型之前**。 ```cpp template <typename T> inline T min(const T&, const T&); // `inline` template <typename T> constexpr T max(cosnt T&, const T&); // `constexpr` ``` <br><br> # 类模版 Class Templates 类模版是使用模版参数来泛型定义一个类的方式,支持类对不同的数据类型进行操作。 类模版在**被使用时(隐式实例化)必须提供模版实参**。编译器不能为**类模版**推断模版参数类型。 > [!NOTE] "类模版" 与 "模版类" 的区别: > > - **类模版**(Class Template):是"模版",是基于模版参数来泛型定义的一个类。 > - **模版类**(Class Generated from a Template):是 "类模版" 经实例化得到的一个具体类。 <br> ## 类模版名的使用 > "**类模版名**" 不是一个**类型名**(type name),**一个实例化的 "==模版类的名称==" 包含==模版实参**==。参见 [^2] > [!NOTE] 类模版的 **=="构造函数名"== 不能带有模版参数**,无论在类模版内外。 ###### 在类模版作用域内使用类模版名 在**类模版作用域的==内部==**,使用 **"类模版名"** 时**可以==省略模版参数==**。<br>此时 **"类模版名"即代表"当前实例化的模版类"**,编译器会根据上下文推导出正确的模版参数。 例如: - 在类模版==内部==**声明数据成员**时; - 在类模版==内部==**声明或定义成员函数**时,函数的**返回类型、形参列表**、以及**函数体内**。 - 在类模版==外部==**定义成员函数**时,函数的**形参列表**中 ###### 在类模版作用域外使用类模版名 在**类模版作用域的==外部==** ,使用"**类模版名**"时 **必须==提供模版参数==**,包括: - 用于**类作用域标识符**时; - **类模版外定义**类模版的成员函数时,函数的**返回类型**中; - 类模版的友元函数中,函数返回类型、函数参数中; 说明示例: ```cpp // 类模版作用域内部, 使用模版名时可省略"模版参数" template <typename T> struct MyClass { MyClass(); MyClass(const MyClass&); MyClass& operator=(const MyClass&); }; // 类模版外定义其成员时, 使用"类模版名"必须提供模版参数. // 自编译器见到"类模版作用域声明"起, 便进入了类模版作用域. // 故"返回类型"中需提供完整类模版名, 而"形参列表"中不需要; template<typename T> MyClass<T>::MyClass() {} template<typename T> MyClass<T>::MyClass(const MyClass& rhs) {} template<typename T> MyClass<T>& MyClass<T>::operator=(const MyClass& rhs) {} ``` <br> ## 类模版成员的声明与定义 在**类模版外**定义类中成员时(成员函数定义、静态数据成员初始化等), 定义前需要**使用 "模版声明"**(`template` 关键字 + 模版参数列表)。 ```cpp title:use_template_class_name.cpp // 定义"类模版" // 在类内部声明或定义成员时, 可以仅使用类模版名而不带模版参数. // 这一情况下, "类模版名"即代表"当前实例化的模版类型", 编译器会根据上下文推导出正确的模版参数. template <typename T> struct MyClass { // 这里的`MyClass` 是一个"类模版名". T content; MyClass *p; static T stc_content; MyClass(T content); // 在类模版内, 构造函数名可以带有模版参数, 为`MyClass<T>(T content)`, 但通常省略. MyClass(const MyClass& rhs); MyClass& operator=(const MyClass& rhs); }; // 类外定义类模版成员时: // 1. 定义前必须带有"模版声明" // 2. 引用类模版名时: // 类作用域标识符中,类模版名"必须带有"模版参数; // 成员函数的"返回类型"中使用类模版名,必须带有模版参数。 // 成员函数的"形参列表"中使用类模版名,可以省略模版参数。 template <typename T> T MyClass<T>::stc_content = 25; // 初始化类模版中的静态成员变量 template <typename T> MyClass<T>::MyClass(T content) { this->content = content; } template <typename T> MyClass<T>::MyClass(const MyClass<T>& rhs) { // `const MyClass<T>&`可省略为`const MyClass&` content = rhs.content; } template <typename T> MyClass<T>& MyClass<T>::operator=(const MyClass<T>& rhs) { if (this != &rhs) { content = rhs.content; } return *this; } ``` <br> ## 类模版的成员函数 类模版的成员函数可以**在类内(为内联)或类外定义(==必须与类定义放在同一个头文件中==)**。 类模版的**成员函数默认==只有在被使用到时才进行实例化==**。 (因此允许成员函数为一个"函数模版") > [!caution] 为保证类模版被正确的实例化和链接,**类模版的成员函数的定义**必须与**类模版的定义**放在**同一个头文件**中。 > > 因为模版在 C++中是 "编译时" 实例化的,而**编译器在实例化类模版时,必须要看到模版的完整定义才能生成模版实例的代码**。 > > ![[02-开发笔记/01-cpp/预处理相关/cpp-头文件说明#^cpj1sg]] > 在**类定义的内部**定义成员函数: ```cpp title:my_class_template.h template<typename T> struct MyClass { void SomeFunc() { // ... } }; ``` 在**类定义外部、类定义所在的头文件中**定义成员函数: ```cpp title:my_class_template.h template<typaname T> struct MyClass { void SomeFunc(); }; // 在类定义外部, 类定义所在的头文件中定义成员函数。 // 需要在定义前进行"模版声明" template<typename T> void MyClass<T>::SomeFunc() { // 指明`MyClass<T>` // ... } ``` ## 类模版的静态成员 类模板的**每一个不同的实例化==模版类==**,**各自拥有一份独立的==静态数据成员==实例**。 ```cpp title:static_member_in_class_template.cpp template <typename T> struct MyClass { static T stc_content; static int count; }; // 例如, MyClass<int>::count 与 MyClass<double>::count是两个独立的静态数据成员。 template <typename T> T MyClass<T>::stc_content = 25; // 初始化类模版中的静态成员变量 template <typename T> int MyClass<T>::count = 0; ``` > [!NOTE] 对于类模版的静态成员函数,同样只有在**被使用时才会进行实例化**。 <br><br> ## 类模版与友元 当一个类包含一个友元声明时,==**类==与==友元==各自是否为模版相互无关**。 - 如果**类模版**包含一个 "**非模版友元**" (友元函数或友元类),则**友元被授权可以访问==所有该类模版的所有实例==** - 如果**友元自身是模版**,则**类模版**可以授权给**所有友元模版实例**,也可以**只授权给特定实例**。 由此,对**类模版与其友元**可能构成以下关系: - **==一对一==关系**:友元是一个**模版实例**,**依赖于==类模版的模版参数==** 进行**实例化**,则**每个类模版的具体实例**将对应有一个**模版实例友元**。 - **==多对多==关系**:友元是一个**模版**,则对于**该类模版的任意一个具体实例**,其 **==模版友元的所有实例==都是其友元**。 ### 总结 在一个**类或类模版**中,其**友元**可以是: - 一个常规友元(友元函数或友元类):友元可以访问**这个类或类模版所有实例**的私有成员 - **一个==模版"实例"**==(模版函数或模版类)作为友元:效果同上; - **一个==模版==**(函数模版或类模版)作为友元:**该模版的==所有实例==** 都是这个类或类模版实例的**友元** > [!tip] **"类模版"本身**可以作为其自己的 "**==模版实例友元==**" 或 "**==模版友元==**",表示**将其自身的==某个实例或其他所有实例==声明为友元**,从而允许**不同类型的实例互相访问私有成员**。 > **类模版中,五种友元形式的总结说明**: | 友元 | 说明 | | | ----------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------- | --- | | **普通友元** | 友元被授权**可访问该类模版的所有实例类** | | | **模版实例**(该实例接受所属类的模版参数 T) <br>- `friend void Somefunc<T>();` <br>- `friend class OtherClass<T>;` | 由**模版参数 `T` 实例化**的特定友元,可以访问 "**同由模版参数 `T` 实例化**"的类<br><br> | | | **模版实例**(该实例由具体参数实例化)<br>- `friend void func<int>();` <br>- `friend class OtherClass<int>;` | 该**特定实例**可访问该类模版的所有实例类 | | | **模版友元**<br>- `template <typename U> void func(); ` <br>- `template <typename U> class OtherClass`; | **模版友元的所有实例,均可访问该类模版的任何实例**。 | | | **类模版自身实例** or **类模版自身** <br>- `friend class MyClass<int>;` <br>- `template <typename U> friend class MyClass;` | 该类模版的任何实例,可被**该类模版自身的某一特定实例** or **其他任何实例**进行访问 | | | **类模版的模版类型参数** <br>- `friend T;` | 该类型模版参数 T,可以访问该类模版的任何实例。 | | 示例: > [!caution] 友元是 "模版实例" 时,需要有该 "模版" 的前置声明; ```cpp title:three_kinds_friend_compare.cpp // 类模版的前置声明 // 声明友元模版类`friend class TemplateClass<T>`所需 template <typename> class TemplateClass; // 友元函数的前置声明 void SomeFunc(); // 函数模版的前置声明 // 声明友元模版函数`friend void TemplateFunc<>(const T&)`所需. template <typename> class MyClass; // 由于模版函数依赖于模版类`MyClass`, 因此还需在其之前声明模版类. template <typename T> void TemplateFunc(const MyClass<T>&); template <typename T> struct MyClass { // 常规友元类 friend class OtherClass; // 以模版类实例作为友元, 需要"类模版"的前置声明; friend class TemplateClass<T>; // 该友元以T实例化, 则只能访问同以T实例化的模版类 friend class TemplateClass<int>; // 该友元以特定模版参数实例化, 则其能访问该类模版的任何实例. // 以类模版作为友元 template <typename U> friend class ClassTemplate; // 以常规函数作为友元. 需要前置声明 friend void SomeFunc(); // 以模版函数实例作为友元, 需要"函数模版"的前置声明. friend void TemplateFunc<>(const MyClass<T>&); // 该友元以T实例化, 则只能访问同以T实例化的模版类 friend void TemplateFunc<int>(const MyClass<int>&); // 该友元以特定模版参数实例化, 则其能访问该类模版的任何实例. // 以函数模版作为友元 template<typename U> friend void FuncTemplate(const MyClass<U>&); // 以该类模版自身的特定实例作为友元. friend class MyClass<int>; // 以该类模版自身的任意实例作为友元 => 使得该类模版任意实例之间均互为友元, 可互相访问; template <typename U> friend class MyClass;     // 以其自身的类型模版参数作为友元.     friend T; }; int main() { MyClass<int> obj; } ``` ### 以 "模板实例" 作为友元 示例:"**模版实例**作为友元"(一对一关系) ```cpp // 对`FriendFunc<T>`模版函数前置声明 template <typename> class MyClass; // 由于模版函数依赖于模版类`MyClass`, 因此还需在其之前声明模版类. template <typename T> void FriendFunc(const MyClass<T>&); // 声明模版函数. (注意, 区别于"显式实例化") // 对`OtherClass<T>`模版类的前置声明 template <typename> class FriendClass; template <typename T> struct MyClass { // `Myclass` 是一个模版类, 其包含一个"类模版"数据成员 // 1) "依赖于类模版中模版参数"的模版类友元. // `FriendClase`是依赖于类模版参数`T`来实例化的"模版类"友元. // 下列友元声明只是将一个"模版类"声明为友元, // 因此在类模版外部, 类模版定义之前需要存在有对该模版类本身的"声明". friend class FriendClass<T>; // 2) "依赖于类模版中模版参数"的模版函数友元: // `FriendFunc`是依赖于类模版参数`T`来实例化的"模版函数"友元. // 因此该模版函数友元应当声明为`FriendFunc<T>`, 显式指出其模版参数. 否则编译器将认为是非模版函数. // 模版函数`FriendFunc<T>`与其实参"模版类"`MyClass<T>`具有一对一的对应关系 // 由于下列友元声明是只是将一个"模版函数"实例声明为友元, // 因此在类模版外部, 类模版定义之前存在有对该模版函数本身的"声明". friend void FriendFunc<T>(const MyClass<T>&); private: int val = 11; }; template<typename T> struct FriendClass { // 因此在类模版外部, 类模版定义之前需要存在有对该模版类本身的"声明". void func(const MyClass<T>& obj) { cout << "Invoke the friend class's function. The val of obj is : " << obj.val << "\n"; } }; template <typename T> void FriendFunc(const MyClass<T>& obj) { cout << "Invoke the friend function. The val of obj is : " << obj.val << "\n"; } int main() { MyClass<int> obj_i; MyClass<char> obj_ch; // `FriendFunc<T>`与 `MyClass<T>` 具有一对一的对应关系 FriendFunc(obj_i); // 正确. 编译器根据函数实参推导函数模版参数类型. FriendFunc<int>(obj_i); // 正确 // FriendFunc<char>(obj); // error: `FrienFunc<char>`与`MyClass<int>`不是友元关系 FriendFunc(obj_ch); // 正确. 编译器根据函数实参推导函数模版参数类型. FriendFunc<char>(obj_ch); // 正确 // FriendFunc<int>(obj_ch); // error: `FrienFunc<int>`与`MyClass<char>`不是友元关系 // `FriendClass<T>`与 `MyClass<T>` 具有一对一的对应关系 FriendClass<int> f_obj_i; FriendClass<char> f_obj_ch; f_obj_i.func(obj_i); // 正确 // f_obj_i.func(obj_ch); // error: `FriendClass<int>`与`MyClass<char>`不是友元关系 f_obj_ch.func(obj_ch); // 正确 // f_obj_ch.func(obj_i); // error: `FriendClass<char>`与`MyClass<int>`不是友元关系 } ``` > [!caution] 声明 "模板函数实例" 时,必须在函数名后带有 "**模板实参列表 `<>`**",但**可省略具体的模板实参名**。 > 如果未带有实参列表,则编译器认为是声明一个"普通函数" 作为友元。 示例: ```cpp template <typename T> void TemplateFunc(const T& obj); template <typename T> struct MyClass { // 声明一个"模板函数实例"作为友元 // 省略了模板实参名`T`, 但必须保留模板参数列表`<>` friend void TemplateFunc<>(const T& obj); // friend void TemplateFunc<T>(const T& obj); // 等价于上语句 // 声明一个"普通函数"作为友元 // 注意区别, 此处声明的NotTemplateFunc不是一个"模板函数实例", 而是能接收该类模板实例的普通函数. friend void NotTemplateFunc(const T& obj); }; // 普通函数 void NotTemplateFunc(const MyClass<int>& obj) { // ... } // 函数模板定义 template <typename T> void TemplateFunc(const T& obj) { // ... } int main() { MyClass<int> obj_i; MyClass<char> obj_ch; NotTemplateFunc(obj_i); // NotTemplateFunc(obj_ch); // error: 未定义能接收`MyClass<char>`NotTemplateFunc的重载版本 TemplateFunc(obj_i); TemplateFunc(obj_ch); return 0; } ``` ### 以 "模板" 作为友元 示例:"**模版**作为友元"(多对多关系) ```cpp title:template_as_friend.cpp // 在类或类模版中, 以"模版"(类模版或函数模版)作为友元. // 则"模版"友元的所有实例都是这个类(一对多)或这一类模版所有实例(多对多)的友元 struct NormalClass { // 类模版友元 template <typename U, typename V> friend class Printer; // 函数模版友元 template <typename U, int> friend void Add(const U&, const U&); private: int val = 11; }; template <typename T> struct TemplateClass { // 类模版友元 template <typename U, typename V> friend class Printer; // 函数模版友元 template <typename U, int> friend void Add(const U&, const U&); private: int val = 22; T content; }; template <typename T, typename V> struct Printer { void func(const T& obj, V val) { cout << "Invoke FriendClass::func(). " << " val in obj: " << obj.val << "; " << " val in param: " << val << endl; } }; template <typename T, int init> void Add(const T& lhs, const T& rhs) { cout << "Invoke Add(): " << lhs.val + rhs.val + init << endl; } int main() { NormalClass nor_obj; TemplateClass<int> tem_obj_i; TemplateClass<char> tem_obj_ch; TemplateClass<string> tem_obj_str; // 函数模版`Add`是`NormalClass`和`TemplateClass`的友元 // 因此`Add`的所有实例都是`NormalClass`和`TemplateClass`的友元 Add<NormalClass, 10>(nor_obj, nor_obj); Add<NormalClass, 20>(nor_obj, nor_obj); Add<TemplateClass<int>, 10>(tem_obj_i, tem_obj_i); Add<TemplateClass<int>, 20>(tem_obj_i, tem_obj_i); Add<TemplateClass<char>, 55>(tem_obj_ch, tem_obj_ch); Add<TemplateClass<string>, 100>(tem_obj_str, tem_obj_str); // 类模版`Printer`是`NormalClass`和`TemplateClass`的友元 // 因此`Printer`的所有实例都是`NormalClass`和`TemplateClass`的友元 Printer<NormalClass, int> f_nor_obj_i; f_nor_obj_i.func(nor_obj, 123); Printer<NormalClass, char> f_nor_obj_ch; f_nor_obj_ch.func(nor_obj, 'A'); Printer<TemplateClass<int>, int> f_tem_i_obj_i; f_tem_i_obj_i.func(tem_obj_i, 123); Printer<TemplateClass<int>, char> f_tem_i_obj_ch; f_tem_i_obj_ch.func(tem_obj_i, 'D'); Printer<TemplateClass<char>, char> f_tem_ch_obj_ch; f_tem_ch_obj_ch.func(tem_obj_ch, 'E'); Printer<TemplateClass<string>, char> f_tem_str_obj_ch; f_tem_str_obj_ch.func(tem_obj_str, 'F'); } ``` ### 让"类模版"的所有实例互相作为彼此的友元 示例:以 **"类模版"自身的其他实例** 作为其自己的友元 ```cpp title:all_instances_of_a_class_template_as_friends_with_each_other.cpp <typename T> class MyClass { // 所有`MyClass`类模版的实例都是彼此的友元. // 从而允许不同类型的实例互相访问私有成员 template <typename U> friend class MyClass; public: MyClass(T val) : data(val){ } // 模版函数, 用于访问另一个MyClass模版实例的私有成员 template <typename U> void func(const MyClass<U>& obj) { cout << "Accessing friend's private data: " << obj.data << "\n"; } private: T data; }; int main() { MyClass<int> obj_i(154); MyClass<char> obj_ch('G'); MyClass<string> obj_str("Hello"); // MyClass的所有实例都是彼此的友元, 因此可以互相访问私有成员 obj_i.func(obj_ch); obj_i.func(obj_str); obj_ch.func(obj_i); obj_ch.func(obj_str); obj_str.func(obj_i); obj_str.func(obj_i); } ``` <br><br><br> # 成员模版 Member Templates "**成员模板**"(Member Templates)是定义在类或类模版内部的 「**==成员函数模版==**」[^3]。 > [!NOTE] 类模版的**成员函数默认==只有在被使用到时才进行实例化==**,因此成员函数可以是一个 "函数模版"。 成员模板允许**函数接受或返回泛型类型**,使得类能够**以通用的方式处理不同的数据类型**。 在一个**普通类或类模版**中: - 其**数据成员**可以是**一个==实例化的模版类**==(例如实例化的容器类) - 其**成员函数**(除虚函数)可以是一个 "==**函数模版**==",即称之为 "**==成员模版==**"。 - 其**内部**可以 **==嵌套==** 一个 "==**类模版**=="; > [!caution] **成员模版不能是==虚函数==,可以是除虚函数以外的任何成员函数**,包括构造函数等。 > [!NOTE] **类模版**与其**成员模版**具有**各自独立的模版参数**。 > 当在**类模版外**为**成员模版**进行定义时,**必须同时为类模版和成员模版提供模版参数列表** > (各自使用独立的 `template <...>` 模版声明语句——类模版的模版参数列表在前,成员模版的模版参数列表在后)。 类模版中的成员模版说明实例: ```cpp template <typename T> struct MyClass { // `Myclass` 是一个模版类 // 类模版中的"成员函数"可以是"函数模版", 即为"成员模版" template <typename U> void MemberFunc(U arg); template <typename U> static void StaticMemberFunc(U arg); }; // 在类模版外定义类模版中的"成员函数模版". // 必须同时提供"类模版的模版参数", 以及"成员模版的模版参数". 二者使用独立的语句. template <typename T> // T和U不能放在同一个模版参数列表中, 因为是属于不同的模版的参数. template <typename U> void MyClass<T>::MemberFunc(U arg) { cout << arg << endl; } template <typename T> template <typename U> void MyClass<T>::StaticMemberFunc(U arg) { cout << arg << endl; } ``` <br><br> ## 成员模版的使用场景 成员模版的常见使用场景包括: - **泛型算法实现**:例如一个类可能提供一个泛型排序函数,对任意类型元素数组排序。 - **泛型数据结构**:例如一个类可能需要内部使用一个**泛型栈或队列**来存储数据。 具体来说,示例有: - **泛型构造函数**和**泛型赋值操作** - **容器类**的**通用插入和获取操作** - **类型转换操作**:将类类型转化为其他多种泛型 - **回调函数和委托**:使用成员模板来**注册和调用不同签名的回调函数**,这**在实现事件处理系统或委托调用时特别有用**。 ### 泛型构造函数和赋值操作 ###### 使用示例:**泛型构造函数** **构造函数成员模版**可称之为"**泛型构造函数**",提供了用于“**对象被复制时给予隐式类型转换**”的能力。 泛型构造函数**并不会压制对 "拷贝或移动构造函数" 的调用**,无论是在**显式类型转换还是隐式类型转换**中,如果**源类型与拷贝/移动构造函数的==参数类型完全吻合==,则他们将被调用**。 ```cpp template <typename T> class MyClass { public: // template构造函数: 具有隐式类型转换的复制构造函数 template <typename U> MyClass(const Myclass<U> &x); // 复制构造函数 MyClass(const Myclass<T> &x); ... }; void f() { MyClass<double> xd; ... MyClass<double> xd2(xd); // calls implicitly generated copy constructor MyClass<int> xi(xd); // calls template constructor } ``` 示例二: ```cpp template <typename T> class MyClass { public: MyClass() : ptr{} {} // 模版构造函数, 可接受不同类型的迭代器 template <typename It> MyClass(It b, It e); private: std::shared_ptr<std::vector<T>> ptr; }; template <typename T> template <typename It> MyClass<T>::MyClass(It b, It e): ptr(std::make_shared<std::vector<T>>(b, e)) { } int main() { int arr[] = { 0, 1, 2, 3, 4, 5 }; vector<long> vi = { 99, 98, 97, 96, 95 }; list<const char*> w = { "now", "is", "the", "time" }; // 将实例化一个模版构造函数MyClass<int>::MyClass(int*, int*); MyClass<int> a1(begin(arr), end(arr)); // 将实例化一个模版构造函数MyClass<int>::MyClass(vector<long>::iterator, vector<long>::iterator); MyClass<int> a2(vi.begin(), vi.end()); // 将实例化一个模版构造函数MyClass<int>::MyClass(list<const char*>::iterator, list<const char*>::iterator); MyClass<string> a3(w.begin(), w.end()); return 0; } ``` ###### 使用示例:实现**类模版不同实例之间的互相赋值** ```cpp template <typename T> class MyClass { public: template <typename U> MyClass<T>& operator=(const MyClass<U>& obj) { // 这里不需要再特别处理自赋值的情况, 能够包含. // 并且`this == &obj`的比较是编译器不允许的, 因为二者类型不同. cout << "Assigning from " << typeid(obj).name() << " to " << typeid(*this).name() << endl; // 形参`obj`的类型是`MyClass<U>`, 而`this`的类型是`MyClass<T>`, 二者类型不同. // 因此不可以直接取`obj`的私有成员`value`, 需要通过`getValue`函数来获取. value = static_cast<T>(obj.getValue()); return *this; } T getValue() const { return value; } private: T value; }; int main() { MyClass<int> obj_i; MyClass<double> obj_d; obj_i = obj_d; return 0; } ``` ### 容器类的通用插入和获取操作 ```cpp template <typename T> class Container { public: // 插入不同类型的数据 template <typename U> void insert(const U& data) { // 插入逻辑 } // 从另一个容器获取数据 template <typename U> void getFrom(const Container<U>& other) { // 获取逻辑 } }; ``` ### 类型转换操作 ```cpp template <typename T> class Numeric { public: // 转换为不同的数值类型 template <typename U> U toType() const { return static_cast<U>(value); } private: T value; }; ``` ### 回调函数和委托 ```cpp #include <functional> class EventDispatcher { public: // 注册具有任意签名的回调函数 template <typename Callback> void registerEvent(std::string eventName, Callback cb) { // 注册逻辑 } // 触发事件 void triggerEvent(std::string eventName) { // 触发逻辑,调用对应的回调函数 } }; ``` <br><br> # 变量模版 since C++14。 例如,下图中声明的即为 "**变量模版**"。 ![[_attachment/02-开发笔记/01-cpp/模版与泛型编程/cpp-模版类别.assets/IMG-cpp-模版类别-C7420CFD18257CE64C407205E1F45BA2.png|473]] <br><br> # Buffer ## 闪念 > sudden idea ## 候选资料 > Read it later # ♾️参考资料 # Footnotes [^1]: 《Effective Modern C++》Item9 [^2]: 《C++Primer》P588 [^3]: 《C++Primer》P595 [^5]: 《C++Primer》P607