文章目录

  • 1.函数模板的特例化
    • 1.1 函数模板的全特化
    • 1.2 函数模板不能偏特化
    • 1.3 函数模板、函数模板的全特化、普通函数
  • 2.类模板的特例化
    • 2.1 类模板的全特化
    • 2.2 类模板成员函数的全特化
    • 2.3 类模板的偏特化
      • 2.3.1 根据模板参数数量进行偏特化
      • 2.3.2 根据模板参数范围进行偏特化

特例化:模板本来是一组通用逻辑的实现,但是对于某些特定的参数类型来说,通用的逻辑实现可能不能满足要求,这时就需要针对这些特殊的类型去实现一个特例模板,即模板的特例化。

全部特例化(全特化):必须有一个主模板(泛化版本),且模板参数被全部指定成具体的类型。

部分特例化(偏特化):必须有一个主模板(泛化版本),且模板参数被部分指定成具体的类型。

1.函数模板的特例化

1.1 函数模板的全特化

函数模板的全特化等价于函数模板针对特定类型的一个实例化,并不等价于一个函数重载,不能将函数模板的全特化与函数重载混为一谈。

  • 如果使用普通重载函数,那么不管是否发生实际的函数调用,都会在目标文件中生成该函数的二进制代码。
  • 如果使用函数模板的全特化版本,除非发生函数调用,否则不会在目标文件中包含全特化模板函数的二进制代码,这符合函数模板的“惰性实例化”准则。

如下代码所示,对于某些类型(例如字符串类型)来说,编译器默认实例化出来的模板代码的处理逻辑是错误的,此时,我们可以为其提供特例化版本。

#include <iostream>
#include <cstring>
using namespace std;// Greater是一个函数模板
template <typename T>
bool Greater(T a, T b)
{cout << "Greater<T>(T a, T b)" << endl;return a > b;
}// 针对Greater函数模板,提供const char*类型的特例化版本
template <>
bool Greater<const char*>(const char* a, const char* b)
{cout << "Greater<const char*>(const char* a, const char* b)" << endl;return strcmp(a, b) > 0;
}int main()
{cout << Greater("hello", "world") << endl;return 0;
}

1.2 函数模板不能偏特化

由于函数重载特性的存在,函数模板只能全特化,不能偏特化。

1.3 函数模板、函数模板的全特化、普通函数

调用优先级:普通函数 > 函数模板的全特化 > 函数模板。

#include <iostream>
#include <cstring>
using namespace std;// Greater是一个函数模板
template <typename T>
bool Greater(T a, T b)
{cout << "Greater<T>(T a, T b)" << endl;return a > b;
}// 针对Greater函数模板,提供const char*类型的特例化版本
template <>
bool Greater<const char*>(const char* a, const char* b)
{cout << "Greater<const char*>(const char* a, const char* b)" << endl;return strcmp(a, b) > 0;
}// 普通函数
bool Greater(const char* a, const char* b)
{cout << "Greater(const char* a, const char* b)" << endl;return strcmp(a, b) > 0;
}int main()
{cout << Greater("hello", "world") << endl;return 0;
}

2.类模板的特例化

2.1 类模板的全特化

#include <iostream>
using namespace std;template <typename T, typename U>
class A    // 主模板
{public:A() { cout << "A<T, U>::A()" << endl; }void fun() { cout << "A<T, U>::fun()" << endl; }
};template <>
class A<int, int>    // 类模板的全特化
{public:A() { cout << "A<int, int>::A()" << endl; }void fun() { cout << "A<int, int>::fun()" << endl; }
};template <>
class A<int, char>    // 类模板的全特化
{public:A() { cout << "A<int, char>::A()" << endl; }void fun() { cout << "A<int, char>::fun()" << endl; }
};int main()
{A<int, int> aii;aii.fun();A<int, char> aic;aic.fun();A<int, double> aid;aid.fun();return 0;
}

输出结果如下:

2.2 类模板成员函数的全特化

#include <iostream>
using namespace std;template <typename T, typename U>
class A    // 主模板
{public:A() { cout << "A<T, U>::A()" << endl; }void fun() { cout << "A<T, U>::fun()" << endl; }
};template <>
class A<int, int>    // 类模板的全特化
{public:A() { cout << "A<int, int>::A()" << endl; }void fun() { cout << "A<int, int>::fun()" << endl; }
};template <>
class A<int, char>    // 类模板的全特化
{public:A() { cout << "A<int, char>::A()" << endl; }void fun() { cout << "A<int, char>::fun()" << endl; }
};template <>
void A<int, double>::fun()    // 类模板成员函数的全特化
{cout << "A<int, double>::fun()" << endl;
}int main()
{A<int, int> aii;aii.fun();A<int, char> aic;aic.fun();A<int, double> aid;aid.fun();return 0;
}

输出结果如下:

2.3 类模板的偏特化

2.3.1 根据模板参数数量进行偏特化

#include <iostream>
using namespace std;template <typename T, typename U, typename W>
class A    // 主模板
{public:A() { cout << "A<T, U, W>::A()" << endl; }void fun() { cout << "A<T, U, W>::fun()" << endl; }
};template <typename U>
class A<int, U, double>    // 类模板根据模板参数数量进行偏特化
{public:A() { cout << "A<int, U, double>::A()" << endl; }void fun() { cout << "A<int, U, double>::fun()" << endl; }
};int main()
{A<int, int, int> aiii;aiii.fun();A<int, char, double> aicd;aicd.fun();return 0;
}

输出结果如下:

2.3.2 根据模板参数范围进行偏特化

从直观上理解,const intint 的范围小,T*T 的范围小,T&T 的范围小,T&&T 的范围小。

#include <iostream>
using namespace std;template <typename T>
class A    // 主模板
{public:A() { cout << "A<T>::A()" << endl; }void fun() { cout << "A<T>::fun()" << endl; }
};template <typename T>
class A<const T>    // 类模板根据模板参数范围进行偏特化
{public:A() { cout << "A<const T>::A()" << endl; }void fun() { cout << "A<const T>::fun()" << endl; }
};template <typename T>
class A<T*>    // 类模板根据模板参数范围进行偏特化
{public:A() { cout << "A<T*>::A()" << endl; }void fun() { cout << "A<T*>::fun()" << endl; }
};template <typename T>
class A<T&>    // 类模板根据模板参数范围进行偏特化
{public:A() { cout << "A<T&>::A()" << endl; }void fun() { cout << "A<T&>::fun()" << endl; }
};template <typename T>
class A<T&&>    // 类模板根据模板参数范围进行偏特化
{public:A() { cout << "A<T&&>::A()" << endl; }void fun() { cout << "A<T&&>::fun()" << endl; }
};int main()
{A<int> a1;a1.fun();A<const double> a2;a2.fun();A<int*> a3;a3.fun();A<const int*> a4;a4.fun();return 0;
}

输出结果如下:

【深入理解C++】函数模板和类模板的特例化相关推荐

  1. 判断exception类型_C++核心准则T.44:使用函数模板推断类模板参数类型(如果可能)...

    T.44: Use function templates to deduce class template argument types (where feasible) T.44:使用函数模板推断类 ...

  2. C++ 泛型编程(一):模板基础:函数模板,类模板,模板原理,模板匹配规则

    类模板 函数模板 泛型编程 泛型编程,泛型即是指具有在多种数据类型上皆可操作的含义,其实就是能够帮助开发者编写完全一般化并可重复使用的算法,同样的工作不需要做多次,同样的算法针对不同的类型也不应该写多 ...

  3. 函数模板和类模板的使用

    函数模板 //交换 int 变量的值 void Swap(int *a, int *b){ int temp = *a; *a = *b; *b = temp; } //交换 float 变量的值 v ...

  4. C++函数模板与类模板的区别

    类模板: C++ 除了支持函数模板,还支持类模板(Class Template).函数模板中定义的类型参数可以用在函数声明和函数定义中,类模板中定义的类型参数可以用在类声明和类实现中.类模板的目的同样 ...

  5. 函数模板、类模板(含模板特化)

    目录 一.函数模板 1.为什么要使用函数模板? 2.函数模板的定义及其使用 3.函数模板的实现原理 4.特例:同名非模板函数能和同名模板函数 同时存在 二.类模板 1.类模板格式 2.使用类模板创建对 ...

  6. 笔记②:牛客校招冲刺集训营---C++工程师(面向对象(友元、运算符重载、继承、多态) -- 内存管理 -- 名称空间、模板(类模板/函数模板) -- STL)

    0618 C++工程师 第5章 高频考点与真题精讲 5.1 指针 & 5.2 函数 5.3 面向对象(和5.4.5.5共三次直播课) 5.3.1 - 5.3.11 5.3.12-14 友元 友 ...

  7. 泛型编程之函数模板和类模板

    1. 函数模板 C++一种编程思想称为泛型编程,主要利用的技术就是模板 C++提供两种模板机制:函数模板和类模板.这里介绍函数模板,类模板在该专题下的另外篇文章中. 函数模板作用:建立一个通用函数,其 ...

  8. C++模板学习02(类模板)(类模板语法、类模板与函数模板的区别、类模板中的成员函数创建时机、类模板对象做函数参数、类模板与继承、类模板成员函数类外实现、类模板分文件编写、类模板与友元)

    C++引用详情(引用的基本语法,注意事项,做函数的参数以及引用的本质,常量引用) 函数高级C++(函数的默认参数,函数的占位参数,函数重载的基本语法以及注意事项) C++类和对象-封装(属性和行为作为 ...

  9. [Reprint] C++函数模板与类模板实例解析

    这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程(Ge ...

  10. 函数模板与类模板(模板类)

    什么是泛型编程? 泛型编程:编写与类型无关的通用代码,是代码复用的一种手段.模板是泛型编程的基础. 模板分为函数模板和类模板 下面我们就来说说函数模板: 函数模板与类型无关,在使用时被参数化,根据实参 ...

最新文章

  1. 罗田用好“大数据”力促扶贫更精准
  2. 网页设计千千万,网站建设万万千
  3. MySQL分区分表 原理详解
  4. Python爬虫自学之第(零)篇——爬虫思路和request模块使用
  5. RBSP、SODB、EBSP三者的区别和联系 SPS: sequence parameter sets
  6. 360极速浏览器 保存的密码 查看
  7. 【题解】(排序) —— POJ 0810:距离排序
  8. 乐鑫ESP32开发 1.Vscode创建新工程,编译,下载烧录,监视端口,点亮一个LED
  9. iOS 25个性能优化/内存优化常用方法
  10. 关注程序员健康之——研究显示白天小睡90分钟将有效增强记忆力
  11. 论文写作之参考文献格式
  12. TP-LINK校招系统测试岗面经汇总
  13. 如何用计算机做文档,在wps上怎么做文档_在wpsoffice上怎么做文档的图文步骤
  14. yolov5系列-yolov5模型部署到web端
  15. linux系统文件夹
  16. 微信小程序-将时间转换成几秒前 几分钟前 几小时前 几天前等时间格式
  17. NFT交易平台2.0来了,源代码,智能合约整套
  18. Linux如何让lst自动对齐,linux自動增加表空間
  19. 麒麟操作系统iso文件中的img文件的解压与压缩
  20. SSM整合之CRUD增删改查案例(非ajax版)

热门文章

  1. [置顶] Android基于Bmob第三方后台开发的App——足说
  2. hadoop常见架构
  3. python爬新闻并保存_利用python的scrapy爬取新浪新闻保存至txt
  4. 一边学计算机一边上班累的说说,「上班」上班累的说说()-说说控
  5. android monkey原理_Android Monkey原理探讨-阿里云开发者社区
  6. 彰显年轻时尚,展现青春魅力------中兴青漾2体验分享
  7. linux桌面怎么解压tar文件,linux安装tar文件,linux怎么解压targz
  8. 微博将在3月16日全部实名制
  9. Treap tree
  10. ALAssetsLibrary读取所有照片