EasyC++模板显式具体化

目录
  • 1.模板显式具体化
  • 2.实例化和具体化

1.模板显式具体化

前文当中说了,模板函数虽然非常好用,但是也存在一些问题。比如有的操作并不是对所有类型都适用的,针对这种情况C++提供了一个解决方案,就是针对特定类型提供具体化的模板定义。这里的具体可以理解成类型的具体。

我们来看一个C++ Primer当中的例子,假设现在我们有一个结构体叫做job:

struct job {
    string name;
    double salary;
    int floor;
}

对于结构体是可以整体赋值的,所以之前的Swap函数对它一样适用。

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

但我们现在希望在交换结构体的时候,只是交换salaryfloor这两个字段,把name保持不变。由于我们希望引入逻辑变化,所以直接调用Swap函数就不可行了。

当然我们可以不用函数模板,直接重载函数:

void Swap(job &a, job &b) {
    // swap为std自带的交换函数,在algorithm头文件中
    swap(a.salary, b.salary);
    swap(a.floor, b.floor);
}

由于C++当中规定,非函数模板的优先级大于函数模板,所以我们在对job结构体调用Swap函数的时候,会优先使用这个。

除此之外,我们还可以提供一个具体化的模板函数:

template <> void Swap<job> (job &a, job &b) {
    swap(a.salary, b.salary);
    swap(a.floor, b.floor);
}

这个函数的写法看起来有些特殊,我们在函数类型之前加上了template <>,在函数名后面又跟上了<job>。它表示的是这是一个函数模板的显式具体化,也可以理解成为之前的函数模板提供一个job类型的版本。C++当中规定显式模板函数的优先级高于普通模板函数。

2.实例化和具体化

关于函数模板,还有一个很重要的概念,就是实例化。

我们在编写代码时,如果只是编写了函数模板本身,编译器是不会为我们生成函数的定义的。当编译器使用模板为特定的类型生成函数定义时,就会得到一个模板的实例。这个概念有点像是Python里的元类,元类的实例是另外一个类。

比如我们定义了一个函数模板:

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

当我们调用它,传入两个int类型的时候,编译器就会生成一个实例,这个实例使用的类型是int。当我们使用double类型的参数又一次调用的时候,编译器会继续生成double类型的实例。这个生成实例的过程是不可见的,所以被称为隐式实例化。

在早年的C++版本当中只支持隐式实例化,但现在C++允许显示实例化。也就意味着我们可以手动命令编译器创建特定的实例,比如Swap<int>() 。语法是通过<>声明指定模板类型,并且在声明之前加上关键字template,如:

template void Swap<int>(int, int);

这个语法看起来和显式具体化非常相似,显式具体化的写法是:

template<> void Swap<int>(int &, int &);
template<> void Swap(int &, int &);

看起来非常相似,但是含义是完全不同的。显式具体化的含义是对于某特定类型不要使用原模板生成函数,而应专门使用指定的函数定义。而显式实例化是使用之前的模板函数的定义的,只不过是手动触发编译器创建函数实例而已。

对了,我们不能同时在一个文件中,使用同一种类型的显式实例化和显式具体化,这会引起报错。

我们如果死记显式实例化的声明,的确很容易和具体化混淆。但我们可以在代码当中直接使用,直接使用的形式则要简单许多,只需要通过<>表明类型即可。

例如:

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

int main() {
 int a = 3;
 double b = 3.5;
 cout << Add<double>(a, b) << endl;
}

在上面这段代码当中,我们通过给Add函数加上了<double>来手动创建了一个接受double类型的函数。需要注意的是,我们传入的a是一个int类型。所以编译器会执行强制类型转换,将它转换成double传入。

到此这篇关于C++模板显式具体化的文章就介绍到这了,更多相关C++模板显式具体化内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C++ 右值引用

    目录 1.左值和右值 2.左值引用和右值引用 文章转自:公众号:Coder梁(ID:Coder_LT) 1.左值和右值 在我们之前的文章当中,介绍的都是左值引用.C++11在左值引用的基础上推出了右值引用,由于是新特性,加上使用的频率也不是很高,有一定的学习成本. 我们先把引用这个概念抛开,先来看看什么是左值什么是右值.其实很简单,左值可以取地址,位于等于号的左侧.而右值没办法取地址,位于等于号的右侧. int a = 4; 比如我们定义了一个int型的变量a,让它的值等于4.其中a位于等于号的

  • C++编写头文件

    文章转自公众号:Coder梁(ID:Coder_LT) 我们之前做的左右示例都是在一个单独的cpp文件当中完成的,当我们要做一个相对复杂或大型的项目时,我们显然不能把所有代码都写在一个cpp里.这就需要我们拆分代码,但代码按照逻辑划分,写入不同的cpp文件当中. 在我们编译的时候,我们可以将这些cpp文件分别单独编译,最后再连接到一起.这样做的好处是,当我们只修改了某一个文件的时候,可以只用单独编译那一个文件,不会影响其他文件的编译结果.一般来说大型项目,都会使用一下自动化的编译工具,比如mak

  • C++模板重载

    目录 1.重载模板 2.问题  文章转自 公众号:Coder梁(ID:Coder_LT) 1.重载模板 函数模板可以使得同一个函数对不同类型使用,非常地方便.但有的时候类型不同,只是通过模板是没办法解决的, 可能逻辑上也会有所区别,这个时候只是使用模板是无法解决的. 为了满足这种需求,我们可以像是重载函数那样重载模板.和常规的函数一样,重载的模板的函数特征,也就是入参的数量和类型必须有所不同. 举个例子:比如我们之前定义了一个函数模板用来交换两个变量的值.如果我们要交换的不只是变量,而是两个数组

  • EasyC++单独编译

    文章转自:微信公众号:Coder梁(ID:Coder_LT) 联合编译: 在上一篇当中,我们编写好了头文件coordin.h,现在我们要完成它的实现 头文件当中只能放一些生命和常量的定义,不能有具体的实现.所以我们要把具体的实现单独放入一个cpp文件当中.因为我们的头文件叫做coordin.h,那么我们与之对应的cpp文件自然就叫做coordin.cpp. 在coordin.h当中我们声明了两个函数,自然我们就要完成这两个函数的实现: #include <cstdio> #include &l

  • C++函数模板介绍

    文章转自: 公众号:Coder梁(ID:Coder_LT) 函数模板: 所谓函数的模板,本质上也就是使用泛型来定义函数. 所谓的泛型其实也就是不定的类型,比如说我们使用vector的时候,可以定义各种类型的vector,可以定义存储int型的vector也可以定义存储float类型的,也可以定义存储其他类型.我们在声明的时候将存储的类型当做参数传给了模板. 泛型可以用具体的类型,比如(int或double)替换,通过将类型作为参数传给模板,编译器会根据传递的参数类型生成该类型的函数.这种方式也被

  • EasyC++自动存储持续性

    转自微信公众号:Coder梁(ID:Coder_LT) 自动存储持续性: 这个概念乍一看有些拗口,其实它很简单,指的是在函数定义中声明的变量的存储持续性是自动的:它们在程序开始执行其所属的函数或代码块时被创建,在执行完函数或代码块时,它们使用的内存被释放. 在默认情况下,我们在函数中声明的变量和函数的参数都是自动存储持续性,它的作用于为局部,没有链接性. 这里的链接性描述了名称如何在不同的单元之间共享,链接性为外部的名称可以在文件之间共享,链接性为内部的名称只能由一个车文件中的函数共享.自动变量

  • 详解C++中的自动存储

    C++有3种管理数据内存的方式即自动存储(栈存储).静态存储和动态存储(堆存储).在不同的方式下,内存的分配形式和存在时间的长短都不同. 下面对自动存储进行说明. 自动存储(栈存储) 对于函数的形参.内部声明的变量及结构变量等,编译器将在函数执行时为形参自动分配存储空间,在执行到变量和结构变量等的声明语句时为其自动分配存储空间,因此称其为自动变量(Automatic Variable),有的教科书也称其为局部变量,在函数执行完毕返回时,这些变量将被撤销,对应的内存空间将被释放. 事实上,自动变量

  • EasyC++模板显式具体化

    目录 1.模板显式具体化 2.实例化和具体化 1.模板显式具体化 前文当中说了,模板函数虽然非常好用,但是也存在一些问题.比如有的操作并不是对所有类型都适用的,针对这种情况C++提供了一个解决方案,就是针对特定类型提供具体化的模板定义.这里的具体可以理解成类型的具体. 我们来看一个C++ Primer当中的例子,假设现在我们有一个结构体叫做job: struct job { string name; double salary; int floor; } 对于结构体是可以整体赋值的,所以之前的S

  • C++模板显式具体化

    出品 | 公众号:Coder梁(ID:Coder_LT) 前文当中说了,模板函数虽然非常好用,但是也存在一些问题.比如有的操作并不是对所有类型都适用的,针对这种情况C++提供了一个解决方案,就是针对特定类型提供具体化的模板定义.这里的具体可以理解成类型的具体. 我们来看一个C++ Primer当中的例子,假设现在我们有一个结构体叫做job: struct job { string name; double salary; int floor; } 对于结构体是可以整体赋值的,所以之前的Swap函

  • C++11中模板隐式实例化与显式实例化的定义详解分析

    目录 1. 隐式实例化 2. 显式实例化声明与定义 3. 显式实例化的用途 1. 隐式实例化 在代码中实际使用模板类构造对象或者调用模板函数时,编译器会根据调用者传给模板的实参进行模板类型推导然后对模板进行实例化,此过程中的实例化即是隐式实例化. template<typename T> T add(T t1, T2) { return t1 + t2; } template<typename T> class Dylan { public: T m_data; }; int ma

  • 详解在C++中显式默认设置的函数和已删除的函数的方法

    在 C++11 中,默认函数和已删除函数使你可以显式控制是否自动生成特殊成员函数.已删除的函数还可为您提供简单语言,以防止所有类型的函数(特殊成员函数和普通成员函数以及非成员函数)的参数中出现有问题的类型提升,这会导致意外的函数调用. 显式默认设置的函数和已删除函数的好处 在 C++ 中,如果某个类型未声明它本身,则编译器将自动为该类型生成默认构造函数.复制构造函数.复制赋值运算符和析构函数.这些函数称为特殊成员函数,它们使 C++ 中的简单用户定义类型的行为如同 C 中的结构.也就是说,可以创

  • django将图片上传数据库后在前端显式的方法

    1.使用ImageField先安装pillow模块 pip install pillow 2.在app的models中设置 class Image(models.Model): pic_name=models.CharField('图片',max_length=40) pic_path=models.ImageField(upload_to="pic_folder/",default='pic_folder/None/no_image.pig') 3.在app的view中设置获取图片的

  • Java并发编程之显式锁机制详解

    我们之前介绍过synchronized关键字实现程序的原子性操作,它的内部也是一种加锁和解锁机制,是一种声明式的编程方式,我们只需要对方法或者代码块进行声明,Java内部帮我们在调用方法之前和结束时加锁和解锁.而我们本篇将要介绍的显式锁是一种手动式的实现方式,程序员控制锁的具体实现,虽然现在越来越趋向于使用synchronized直接实现原子操作,但是了解了Lock接口的具体实现机制将有助于我们对synchronized的使用.本文主要涉及以下一些内容: 接口Lock的基本组成成员 可重入锁Re

  • 浅谈C++ Explicit Constructors(显式构造函数)

    C++ 为类(Class)提供了许多默认函数.如果自己没有申明,编译器会为我们提供一个copy构造函数.一个copy assignment操作符和一个析构函数.此外,如果没有申明任何构造函数,编译器会为我们申明一个default构造函数.很像下面的Empty类: class Empty{ public: Empty(); Empty(const Empty &rhs); ~Empty(); Empty& operator=(const Empty &rhs); }; 就像Effec

  • sqlsever为标识列指定显式值

    sqlsever为标识列指定显式值的问题,大多是大家在两个结构完全相同的表,由其中一个表插入另一个表中指定条件的数据,报如下错误: 仅当使用了列列表并且 IDENTITY_INSERT 为 ON 时,才能为表'*'中的标识列指定显式值. 在网上找到了解决方案,亲自试过,可以解决. 一.问题详述如下: 系统:windows2003 数据库:2005 数据库实例:wzgl2004 和wzgl2003,这两个实例都有表kc 执行语句 insert into wzgl2004.dbo.kc select

  • 在SQL Server数据库中为标识(IDENTITY)列插入显式值

    如果我们在标识列中插入值,例如: insert member(id,username) values(10,'admin') 则在查询分析器里面会返回错误信息:  引用内容 服务器: 消息 544,级别 16,状态 1,行 1 当 IDENTITY_Insert 设置为 OFF 时,不能向表 'member' 中的标识列插入显式值. 而在ASP程序中会返回错误信息:  引用内容 Microsoft OLE DB Provider for SQL Server 错误 '80040e14' 当 ID

  • 详解Oracle隐式游标和显式游标

    游标是什么?就是在内存开辟的一块临时存储空间. 1.Oracle隐式游标 1.1Oracle有常用的哪些隐式游标 1.2 Oracle隐式游标演示 -- 隐式游标 (使用的表为Oracle默认自带的emp表) -- sql%rowcount:影响记录条数 sql%found:是否有满足条件的记录 set serveroutput on; declare v_ename a_emp.ename%type; begin select ename into v_ename from a_emp whe

随机推荐