类模板详解

C++——详解类模板与友元函数 模板类的友元函数有三类: 1)非模板友元函数:友元函数不是模板函数,而是利用模板类参数生成的函数。2)约束模板友元函数:模板类实例化时,每个实例化的类对应一个友元函数。 3)非约束模板友元函数:模板类实例化时,如果实例化了n个类,也会实例化n个友元函数,每个实例化的类都拥有n个友元函数。 阅读详情

模板类以下面的代码开头:

 template <class Type>

可以使用关键字typename代替class:
template <typename Type> //newer choice

 

可以使用自己的通用类型名代替Type,其命名规则与其他标识符相同。

 

模板还可以包含多个类型参数
template<class T1,class T2>

 

    通用类型标识符——例如这里的Type——称为类型参数(type parameter),这意味着它们类似于变量,但赋给它们的不能是数字,而只能是类型。

 

假设有类stack:
typedef unsigned long Item;

class stack
{private:
    enum{MAX=10};
    Item items[MAX];
    ...
 public:
    bool push(const Item & item);
    ...
};

 

建立模板类时,应将声明中标识Item的所有typedef替换为Type:
Item items[MAX];
bool push(const Item & item);

改为:
Type items[MAX];
bool push(const Type & item);

 

在模板类中使用模板成员函数,每个函数头都将以相同的模板声明打头:
template <class Type>

 

并使用通用类型名Type替换typedef标识符Item。另外,还需将限定符从stack::改为stack<Type>::。例如:
bool stack::push(const Item & item){...}
改为:
template <class Type>
bool stack<Type>::push(const Type & item){...}

 

在类外面,即指定返回类型或使用作用域解析符时,必须使用完整的stack<Type>
(如果在类声明中定义了方法即内联定义,则可以省略模板前缀和类限定符)

 

    除非编译器实现了新的export关键字,否则将模板成员函数放置在一个独立的实现文件中将无法运行。因为模板不是函数,它们不能单独编译。模板必须与特定的模板实例化请求一起使用。为此,最简单的方法是将所有模板信息放在一个头文件中,并在要使用这些模板的文件中包含该头文件。

 

    如果编译器实现了export关键字,则可以将模板方法定义放在一个独立的文件中,条件是每个模板声明都以export开始:
export template <class Type>   // preface with export
class stack { ... };

 

然后按常规类的方式进行:
1.将模板类声明(包含关键字export)放在一个头文件中,并使用#include编译指令使程序能够使用这些声明。
2.将模板类的方法定义放在一个源代码文件中,在该文件中包含头文件,并使用工程文件(或其他等有效文件)使程序能够使用这些定义。

 

使用模板类
声明一个类型为模板类的对象,方法是使用所需的具体类型替换通用类型名:

stack<int> kernels;       // create a stack of ints
stack<string> colonels; // create a stack of string objects

 

    必须显示地提供所需的类型,这与常规的函数模板是不同的。可以将内置类型或类对象用作类模板的类型。但如果是指针,则需要对程序做重大修改,否则无法很好的工作。

 

数组模板范例和非类型参数

template <class T,int n>
class ArrayTP
{private: T ar[n];
  ... };

 

int指出n的类型为int,这种参数——指定特殊的类型而不是用作通用类型名,称为非类型(non-type)或表达式(expression)参数。

 

ArrayTP<double,12> eggweights;


将导致编译器定义名为ArrayTP<double,12>的类,并创建一个类型为ArrayTP<double,12>的eggweights对象。定义类时,编译器将使用double替换T,使用12替换n。

 

    表达式参数可以是整形、枚举、引用或指针。模板代码不能修改参数的值,也不能使用参数的地址。所以,在ArrayTP模板中不能使用诸如n++和&n等表达式。在实例化模板时,用作表达式参数的值必须是常量表达式。

 

模板类可以用作基类,也可用作组件类,还可用作其他模板的类型参数。

 

例如,可以使用数组模板实现堆栈模板,也可以使用数组模板来构造数组——数组元素是基于堆栈模板的堆栈:
template<class T>
class Array { private: T entry; ... };

template<class Type>
class GrowArray: public Array<Type> {...}; //inheritance

template<class Tp>
class stack
{ Array<Tp> ar;        //use an Array<> as a component
  ... };

...
Array < stack<int> > asi;    // an array of stacks of int


(最后一条语句中,必须使用至少一个空白字符将两个>符号分开,以避免与>>操作符混淆)

 

递归使用模板


例如,对于前面的数组模板定义,可以这样使用:
ArrayTP< ArrayTP<int,5>,10> twodee;

 

这使得twodee是一个包含10个元素的数组,其中每个元素都是一个包含5个int元素的数组。与之等价的常规数组声明如下:
int twodee[10][5];


(在模板句法中,维的顺序与等价的二维数组相反)

 

默认类型模板参数


可以为类型参数提供默认值:
template<class T1,class T2 = int> class Topo {...};

 

如果省略T2的值,编译器将使用int:
Topo<double,double> m1;    //T1 is double,T2 is double
Topo<double> m2;           //T1 is double,T2 is int

 

(可以为类模板类型参数提供默认值,但不能为函数模板参数提供默认值。不过可以为非类型参数提供默认值,这对于类模板和函数模板都是适用的)

 

模板具体化

1.隐式实例化(implicit instantiation)

 

编译器使用通用模板提供的处方生成具体的类定义:
stack<int> stuff;    // implicit instantiation

 

编译器在需要对象之前,不会生出类的隐式实例化:
stack<int> *pt;             //a pointer,no object needed yet
pt = new stack<int>;    //now an object is needed


第二条语句导致编译器生出类定义,并根据该定义创建一个对象。

 

2.显示实例化(explicit instantiation)


当使用关键字template并指出所需类型来声明类时,编译器将生成类声明的显示实例化。声明必须位于模板定义所在的名称空间中。例如:
template class stack<int>; //generate stack<int> class

 

将stack<int>声明为一个类。虽然没有创建或提及类对象,编译器也将生成类声明(包括方法定义)。和隐式实例化一样,也将根据通用模板来生成具体化。

 

3.显示具体化(explicit specialization)

 

有时候,可能需要在为特殊类型实例化时,对模板进行修改,使其行为不同。这种情况下,可以创建显示具体化:
template<> class classname<specialized-type-name> {...};
早期的格式为:
class classname<specialized-type-name> {...};

 

<specialized-type-name>改为特定的类型即可。

 

当具体化模板和通用模板都与实例化请求匹配时,编译器将使用具体化版本。

 

4.部分具体化(partial specialization)

 

即部分限制模板的通用性,例如,可以给类型参数之一指定具体的类型:
// general temlpate
template <class T1,class T2> class Pair {...};
// specialization with T2 set to int
template <class T1> class pair<T1,int> {...};

 

关键字template后面的<>声明是没有被具体化的类型参数。因此,上诉第二个声明将T2具体化为int,但T1保存不变。如果指定所有的类型,则<>内将为空,这将导致显示具体化:
// specialization with T1 and T2 set to int
template <> class Pair<int,int> {...};

 

如果有多个模板可供选择,则编译器将使用具体化程度最高的模板:
Pair<double,double> p1;   //use general Pair template
Pair<double,int> p2;      //use Pair<T1,int> partial specialization
Pair<int,int> p3;         //use Pair<int,int> explicit specialization

 

也可以通过为指针提供特殊版本来部分具体化现有的模板:
template<class T>         //general version
class Feeb {...};
template<class T*>
        //pointer partial specialization
class Feeb {...};         //modified code

(如果提供的类型不是指针,则编译器将使用通用版本;如果提供的是指针,则编译器将使用指针具体化版本)

Feeb<char> fb1;       //use general Feeb template,T is char
Feeb<char *> fb2;     //use Feeb T* specialization,T is char
(如果没有进行部分具体化,则第二个声明将使用通用模板,将T转换为char *类型。如果进行了部分具体化,则第二个声明将使用具体化模板,将T转换为char。)

 

部分具体化特性使得能够设置各种限制:
//general template
template <class T1,class T2,class T3> class Trio{...};
//specialization with T3 set to T2
template <class T1,class T2> class Trio<T1,T2,T2> {...};
//specialization wih T3 and T2 set to T1*
template <class T1> class Trio<T1,T1*,T1*> {...};

根据上述声明,编译器将作出如下选择:
Trio<int,short,char *> t1;        // use general template
Trio<int,short> t2;               //use Trio<T1,T2,T2>
Trio<char,char *,char *> t3;      //use Trio<T1,T1*,T1*>

 

成员模板
模板类将另一个模板类和模板函数作为其成员:
template <typename T>
class beta
{ private:
     template <typename V>
//nested template class member
     class hold
     { ... };
      hold<T> q;
           //template object
      hold<int> n;         //template object
  public:
     beta(T t, int i): q(t),n(i) {}
     template<typename U>
     U blab(U u,T t) { return (n.value() + q.value() ) * u / t; }
     void show()const { q.show();n.show();}
};

 

如果编译器接受类外面的定义,则可如下编写代码:
template <typename T>
class beta
{private:
    template <typename V>
    // declaration
    class hold;
    hold<T> q;
    hold<int> n;
 public:
    beta(T t, int i): q(t),n(i) {}
    template<typename U>
     // declaration
    U blab(U u,T t);
    void show()const { q.show();n.show();}
};

 

//member definition
template <typename T>
     template <typename V>
     class beta<T>::hold
     { ... };

 

//member definition
template <typename T>
     template <typename V>
     U beta<T>::blab(U u,T t)
     {
       return (n.value() + q.value() ) * u / t;
     }

 

上述定义将T、V和U用作模板参数。因为模板是嵌套的,因此必须使用句法:
template <typename T>
     template <typename V>
而不是:
template <typename T,typename V>


定义还必须指出hold和blab是beta<T>类的成员,这是通过使用作用域解析操作符来完成的。

 

将模板用作参数

 


模板还可以包含本身就是模板的参数:
template <template <typename T> class Thing>
class Crab
{private:
    Thing<int> s1;
    Thing<double> s2;
 ... };

 


上述中模板参数是template <typename T> class Thing,其中template <typename T> class 是类型,Thing是参数。假设有下面的声明:
Crab<king> legs;

为使上述声明被接受,模板参数king必须是一个模板类,其声明与模板参数Thing的声明匹配:
template <typename T>
class king { ... };

 

Crab的声明声明了两个对象:
Thing<int> s1;
Thing<double> s2;

前面的legs声明将用king<int>替换Thing<int>,用king<double>替换Thing<double>。
简而言之,模板参数Thing将被替换为声明Crab对象时被用作模板参数的模板类型。

 

混合使用模板参数和常规参数,如:
template <template <typename T> class Thing,typename U,typenameV>
class Crab
{ private:
     Thing<U> s1;
     Thing<V> s2;
  ... };
成员s1和s2可以存储的数据类型为通用类型,而不是硬编码指定的类型。

LVDS接口总结--(0)LVDS硬件电路接口 xilinx LVDS接口硬件总结 阅读详情

相关推荐

【Qualcomm高通音频】外部Codec调试流程_ES7243E

一、 调试大纲 调试正式开始之前,想办法获取以下信息:硬件设计原理图/Codec参考驱动代码/FAE联系方式。 1. 从硬件设计原理图,我们要获取到Codec芯片和CPU通过什么接口连接,包括数据传输接口、控制接口、reset和power引脚。 2. Codec参考驱动代码,一般正规的厂商都会提供的,至少也提供对应场景的寄存器配置。 接下来开始正式调试,大致分为以下流程: a. 数据...

crow_ch的博客 8264

【C++】模板中template、typename的非常见用法

模板是指:C++程序设计中采用类型作为参数的程序设计,用于支持通用程序设计。C++的标准库提供许多有用的函数大多结合了模板的观念,如STL、IO Stream等。在模型的声明中,最最最常见的用法就是:值得注意的是:模板在编译的时候并不知道这个T是什么类型,只有在实例化的时候才能够知晓。因此,这会导致在模板较复杂的时候,可能会产生很多意想不到的理解上的歧义。为了规避这种歧义性,typename和template在某些特定的情况下,需要点明。这就是它们的非常见用法。

Yngz_Miao的博客 1万+

一觉醒后ChatGPT 被淘汰了

近日,AI 界貌似出现了一种新的趋势:自主人工智能。这不是空穴来风,最近一个名为 AutoGPT 的研究开始走进大众视野。特斯拉前 AI 总监、刚刚回归 OpenAI 的 Andrej Karpathy 也为其大力宣传,并在推特赞扬:「AutoGPT 是 prompt 工程的下一个前沿。」

Rocky006的博客 13万+

模板作为参数

模板作为参数 模板这种也是可以作为参数的 template <template class Thing>,其中template class 就是带一个泛型的类型,Thing是参数,意味着,Thing接受带一个泛型参数的类型. 利用一个类模板作为作为头文件: template <typename Type> class Stack { private: enum {MAX = 10}; // constant specific to class Type it

liutao43的博客 795

华硕ROG玩家国度安装Ubuntu双系统避坑指南:安全启动密钥那些事儿

本文详细解析了在华硕ROG玩家国度设备上安装Ubuntu双系统时,如何正确处理BIOS中的安全启动(Secure Boot)与密钥管理,避免常见的引导失败和Windows系统无法启动问题。指南提供了从数据备份、启动盘制作到BIOS精细设置(如将OS Type改为Other OS而非简单关闭Secure Boot)以及分区规划的完整流程,确保两个系统都能稳定共存。

weixin_29219189的博客 754

AI漫剧制作全流程零基础实操指南:从剧本到剪辑

AI漫剧是一种利用AI工具将剧本、分镜、出图、配音、剪辑整合为流水线的短视频内容形式。其技术原理基于文生图、图生图与文本转语音模型的组合,核心挑战在于角色一致性控制与分镜批量出图。这项技术大幅降低了视频制作门槛,使个人创作者无需演员和设备即可产出剧情向短内容,广泛应用于短视频平台的情景剧、玄幻、甜宠等题材。本文给出了一套零基础可照做的全流程实操方案,覆盖剧本提示词、分镜表、出图选型、配音合成与剪辑模板,帮助你快速跑通AI漫剧制作链路。

weixin_29048309的博客 522

C++将模板类用作参数

C++将模板类用作参数

qq_40135848的博客 594

软件产品国际化:前后端及App多语言版本解决方案(超详细实现过程)

多语言版本解决方案是应对全球化趋势的关键策略,它通过构建灵活且可扩展的架构,支持软件产品在不同语言和文化环境下的顺畅运行与展示。此方案涵盖了前端多语言界面实现、后端多语言数据处理及大数据环境下的多语言支持等多个层面,确保公司能够高效地推出适应全球用户多样化需求的软件产品。在前端多语言界面实现方面,解决方案采用了国际化与本地化的结合方法。国际化过程确保软件的功能和代码设计能够处理多种语言和文化习惯,而本地化则针对特定地区进行界面和内容的调整。

大模型大数据攻城狮的专栏 2752

内联模板

内联函数 内联即inline,首先想到的是内联函数,引入内联函数的目的是为了解决程序中函数调用的效率问题。 内联函数从源代码层看,有函数的结构,而在编译后,却不具备函数的性质。编译时,类似宏替换,使用函数体替换调用处的函数名。 一般在代码中用inline修饰,但能否形成内联函数,需要看编译器对该函数定义的具体处理。 举个例子: inline int add(int x, int y, ...

weixin_38252896的博客 770

详细推导波特图增益和相位曲线

最近因为项目需求,在回看波特图方面的内容。大三那会,《自动控制原理》这本书里面就讲过这些东西,但是那时候总感觉学这些没啥用,反正以后也用不到,对这种课程的重视度不是很高。 工作后发现,只要你从事的是和本专业相关的工作,大学学过的很多理论课程在后面大概率都会用到。曾经那些我们在学校以为用不上的东西,熟不知在后面用处还多着呢。所以啊,仅仅只是我们的以为而已! 现在还在学校的同学,对待《自动控制理论》、《信号与系统》、《通信原理》这样的核心专业课,建议还是好好学习一下,认真听听课。哪怕是考试完以后就会忘掉,但当我

D_Katter的博客 3936

SAP CPI 和 PO 的区别

SAP CPI适合云集成轻量级的集成需求,并且由于其云架构,具有快速部署低维护高度可扩展的特点。SAP PO更适合本地系统集成复杂的集成场景和高度定制化的需求,并且对于已经有 SAP 基础设施的企业来说,PO 提供了更多的控制和灵活性。选择使用哪个平台通常取决于企业的技术架构、集成需求、预算以及对灵活性和控制的需求。如果企业主要使用 SAP 的本地系统,并且有复杂的集成需求,那么 SAP PO 是一个理想的选择。如果企业更多地依赖云应用,并希望简化集成操作,那么 SAP CPI 更加适合。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1870

c++类模板详解

学习目标:掌握类模板成员函数分文件编写产生的问题以及解决方式问题:类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到解决:解决方式1:直接包含.cpp源文件解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制。

m0_62681656的博客 3433

ESP32-C3入门教程 蓝牙篇①——基于Blufi 的 WiFi 智能配网

文章目录一、前言二、WiFi配网方式三、快速运行四、运行效果五、ESP32-C3程序流程5.1 主程序5.2 回调函数5.3 SmartConfig线程5.4 流程图六、关键函数6.1 设置SmartConfig的协议类型6.2 启动SmartConfig6.3 停止SmartConfig七、其他八、参考 一、前言 本文基于VS Code IDE进行编程、编译、下载、运行等操作 基础知识点请查阅:ESP32-C3入门教程 基础篇①——基于VS Code构建Hello World 二、WiFi配网方式 W

7764

C++——详解类模板

函数可以定义函数模板,同样地,对于类来说,也可以定义一个类模板。类模板是针对成员数据类型不同的类的抽象,它不是一个具体实际的类,而是一个类型的类,一个类模板可以生成多种具体的类。类模板的定义格式如下所示:其中,template是声明类模板的关键字,表示声明一个模板,模板参数可以是一个,也可以是多个,可以是类型参数,也可以是非类型参数。类型参数由关键字class或typename及其后面的标识符构成。非类型参数由一个普通参数构成,代表模板定义中的一个常量。该例中,T为类型参数,a为非类型参数。

阿标de杂货铺 980

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C++ 类模板 详解

什么时类模板? 类模板和函数模板总体上差不多,都是进行虚拟替换! https://blog.youkuaiyun.com/cpp_learner/article/details/104390433 为什么要使用类模板? 类模板能够为类的数据成员、成员函数的参数、返回值提供动态参数化的机制,即可以构造不同数据类型的实例。 类模板的定义 类模板由模板说明和类说明构成 模板说明同函数模板,如下: t...

cpp_learner的博客 2801

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C++类模板详解

类模板是一种用来生成类定义的模板,其中可以包含一个或多个类型参数。这些类型参数可以在定义类的时候替换为任意类型,从而使得我们能够创建适用于多种数据类型的通用类定义。类模板的定义使用 template或来声明一个类型参数。

weixin_44115575的博客 5205

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

C++模板、类模板、函数模板详解都在这里了

C++模板、类模板、函数模板详解一、引言二、函数模板1、定义2、调用3、多个虚类型三、类模板1、定义2、调用四、类的函数模板五、类作为数据类型传入六、类模板与继承七、类模板与友元 一、引言 在写排序算法时,如果要写一个交换两个数据的函数,由于基本数据类型有int、float、double等等类型,所以针对每种数据类型可能我们要写很多swap函数,这些函数除了传入的数据类型不同,函数体结构大致相同。...

hsxyfzh的博客 1万+

C++基础——类模板详解

C++模板——类模板 C++中模板类的定义方法 template<class T ,class T1,…> class 类模板名{ 成员变量和成员函数 }; 类模板中成员函数放在模板类外面定义语法: template <类型参数表> 返回值类型 类模板名<类型参数名列表>::成员函数名(参数表) { … } 用类模板定义一个对象写法如下: 类模板名<真实参数类型表> 对象名(构造函数实际参数表); 类模板名<真实参数类型表> 对象名;

weixin_33460831的博客 542

函数/类模板详解

泛型编程是一种编程思想,其追求摆脱数据类型的束缚,通过将数据类型作为参数的处理,提高代码的通用性。模板是泛型编程的基础,它支持将数据类型作为参数,从而使得我们在处理具有相似性的对不同数据类型的处理时大大减少类代码量。模板在定义时并不会占有内存,而是在我们使用模板时针对我们的参数具体产生一个处理此类参数的函数/类,并在此时分配内存,这个过程就叫做模板的实例化。模板大致可以分为函数模板和类模板。两者有很多相似之处,但也略有不同。

2301_78933228的博客 1206

类模板与友元详解

/* 类模板 与 友元 详解 */ //4种情况 //1)、函数、类、类的成员函数作为类模板的友元 //2)、函数模板作为类模板的友元 //3)、函数模板作为类的友元 //4)、类模板作为类模板的友元 #include <iostream> using namespace std; void Func1() {} class A { }; class B { public: void Func() {} template <class T> friend

weixin_43445441的博客 484

C++ 类模板与模板类详解

  在C++的Template中很多地方都用到了typename与class这两个关键字,有时候这两者可以替换,那么这两个关键字是否完全一样呢?   事实上class用于定义类,在模板引入c++后,最初定义模板的方法为:template<class T>,这里class关键字表明T是一个类型,后来为了避免class在这两个地方的使用可能给人带来混淆,所以引入了typename这个关键...

weixin_30907935的博客 6464
上一篇: 多重继承 与 虚基类
下一篇: 模板类和友元函数
TypeCool
博客等级 码龄22年 58粉丝 93原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值