EasyC++模板显式具体化

 更新时间:2021年12月17日 08:45:14   作者:梁唐  
这篇文章主要介绍了C++模板显式具体化,在C++中,可以提供一个具体化函数定义称为具体显式化(explict specialization)。其中包含所需的代码,当编译器找到与函数调用匹配的具体化定义时,将使用该定义,而不再寻找模板,下面我们来看看文章具体介绍吧

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++模板显式具体化内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • QT实现简单打地鼠游戏

    QT实现简单打地鼠游戏

    这篇文章主要为大家详细介绍了QT实现简单打地鼠游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-12-12
  • 详解如何配置CLion作为Qt5开发环境的方法

    详解如何配置CLion作为Qt5开发环境的方法

    这篇文章主要介绍了详解如何配置CLion作为Qt5开发环境的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-04-04
  • 一文读懂C++中的继承之菱形继承(案例分析)

    一文读懂C++中的继承之菱形继承(案例分析)

    这篇文章主要介绍了C++中的继承之菱形继承的相关知识,通过案例给大家详细分析介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2021-04-04
  • Qt5连接并操作PostgreSQL数据库的实现示例

    Qt5连接并操作PostgreSQL数据库的实现示例

    本文主要介绍了Qt5连接并操作PostgreSQL数据库的实现示例,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-12-12
  • C++模拟实现string的方法详解

    C++模拟实现string的方法详解

    标准库类型string表示可变长的字符序列,使用string类型必须首先包含string的头文件。本文将利用C++模拟实现string,需要的可以参考一下
    2022-11-11
  • 聊聊C语言中sizeof运算符的一个陷阱

    聊聊C语言中sizeof运算符的一个陷阱

    在C语言中,sizeof()是一个判断数据类型或者表达式长度的运算符,下面这篇文章主要给大家介绍了关于C语言中sizeof运算符的一个陷阱的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-11-11
  • C语言中strcpy()函数的具体实现及注意事项

    C语言中strcpy()函数的具体实现及注意事项

    C语言库函数char *strcpy(char *dest, const char *src)把src所指向的字符串复制到dest,下面这篇文章主要给大家介绍了关于C语言中strcpy()函数的具体实现及注意事项的相关资料,需要的朋友可以参考下
    2022-11-11
  • C++中string转换为char*类型返回后乱码问题解决

    C++中string转换为char*类型返回后乱码问题解决

    这篇文章主要介绍了C++中string转换为char*类型返回后乱码问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-07-07
  • C++ 类的继承与派生实例详解

    C++ 类的继承与派生实例详解

    这篇文章主要介绍了 C++ 类的继承与派生实例详解的相关资料,需要的朋友可以参考下
    2017-06-06
  • C++文件读取的4种情况汇总

    C++文件读取的4种情况汇总

    前几天要用到C++读取文本文件,就学习了一下几种不同的读取方法,下面这篇文章主要给大家介绍了关于C++文件读取的4种情况,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01

最新评论