C++泛型编程之函数模板

泛型语义

  泛型(Generic Programming),即是指具有在多种数据类型上皆可操作的含意。泛型编
程的代表作品 STL 是一种高效、泛型、可交互操作的软件组件。
  泛型编程最初诞生于 C++中,目的是为了实现 C++的 STL(标准模板库)。其语言支
持机制就是模板(Templates)。
  模板的精神其实很简单:类型参数化(type parameterized),即,类型也是一种参数,
也是一种静多态。 换句话说, 把一个原本特定于某个类型的算法或类当中的类型信息抽掉,
抽出来做成模板参数。

 

函数模板

引子:重载函数,虽然在一定程度上达到了多类型适应的目的,但是不彻底,且有二义性存在。

#include <iostream>
using namespace std;
void myswap(int & a, int &b)
{   
int t = a;   a = b;   b = t; }
void myswap(
double & a, double &b)
{   
double t = a;   a = b;   b = t; }

int main()
{   
long a = 2; long b = 3;   myswap(a,b); //ambiguous   cout<<a<<b<<endl;   return 0; }

 

函数模板

语法:在一个函数的参数表, 返回类型和函数体中使用参数化的类型。

template<typename/class 类型参数 T1, typename/class 类型参数 T2,...>

特点:结构上与普通函数无异,但是在传入参数和返回值上做了泛化

返回类型 函数模板名(函数参数列表)
{
函数模板定义体
}

案例:(概念比较抽象,请通过案例来观察其特点)

 



decltype +auto(c++11新特性)

多种类型混合模板,详情请阅读本人博文《C++11/14的新特性——更简洁》关于decltype的解析。https://www.cnblogs.com/wangkeqin/p/9285682.html

 

#include <iostream>

using namespace std;

template<typename R, typename T,typename U>
R add(T a, U b)
{
    return a+b;
} 

template<typename R, typename T,typename U>
auto add2(T a, U b)->decltype(a+b)
{
    return a+b;
} 

int main(int argc, char *argv[])
{
    int a = 1;
    float b = 1.1;
    auto ret = add<decltype(a+b),int,float>(a,b);
    cout<<ret<<endl;
    auto ret2 = add2<decltype(a+b)>(a,b);
    cout<<ret2<<endl;
    return 0;
}

 

 

 

 

函数模板与普通函数的区别无非就是将函数参数高度抽象化,使其具备处理更多数据类型的能力。

特性小结

1)严格匹配,不存在隐式转化。

2)先实例化,再调用。

3)类型参数可以省略。

4)尺有所长,寸有所短。

 

原理:

  编译器并不是把函数模板处理成能够处理任意类的函数; 编译器从函数模板通过
具体类型产生不同的函数; 编译器会对函数模板进行两次编译: 在声明的地方对模板
代码本身进行编译, 在调用的地方对参数替换后的代码进行编译。

 

函数模板的应用——将快速排序算法实现模板化

#include <iostream>
#include <typeinfo>
using namespace std;

template
<typename T> void quickSort(T * array,int left, int right) {   if(left<right)   {     int low = left; int high = right;     T pivot = array[low];     while(low<high)     {       while(array[high] >= pivot && high>low )         high--;       array[low] = array[high];       while(array[low] <= pivot&& high>low)         low++;       array[high] = array[low];
    }
  array[low]
= pivot;   quickSort(array,left,low-1);   quickSort(array,low+1,right);   } }

int main() {   
int array[10] = {1,3,5,7,2,4,6,8,0,9};   quickSort<int>(array,0,9);   for(auto i:array)   {     cout<<i<<endl;   } }

 

函数模板的默认参数

  函数模板,在调用时,先实例化为模板函数,然后再调用。当然也可以设置默认类
型的默认值。由于系统强大的自动推导能力,有时默认也没有太大的意义。

template<typename T = int>
void quickSort(T * array,int left, int right)

 

模板特化

  就是在实例化模板时,对特定类型的实参进行特殊处理,即实例化一个特殊的实例版本。

template<typename T> int compare( T &a, T &b)
template<> int compare < const char * >( const char* &a, const char* &b)

  当以特化定义时的形参使用模板时,将调用特化版本,模板特化分为全特化和偏特
化,函数模板的特化,只能全特化;

  比如我们在比较两个数的大小时:

#include <iostream>
#include <string.h>
using namespace std;
template
<typename T> int compare( T &a, T &b) {   if(a > b) return 1;   else if(a < b)return -1;   else return 0; }


//实参为两个 char 指针时, 比较的是指针的大小, //而不是指针指向内容的大小, 此时就需要为该函数模板定义一个特化版本, 即特殊处理的版本: template<> int compare < const char * >( const char* &a, const char* &b) {   return strcmp(a,b); }
int main() {   
int a = 3; int b = 5;   cout<<compare(a,b)<<endl;   string str1 = "abc",str2 ="abc";   cout<<compare(str1,str2)<<endl;   char * p1 = "abc",*p2= "def";   cout<<compare(p1,p2)<<endl;   cout<<compare(p2,p1)<<endl;   return 0; }

关于模板特化的认识

模板特化的原因:当前函数模板的逻辑或者功能,不能满足特定参数的需求。

模板特化的方式:将需要特化的参数提前”布置“到模板中去,提前预定模板,之后传入需要特化的参数时便可以

优先调用经过该参数特化的模板。

 

适用场景

  函数模板,只适用于函数的参数个数相同而类型不同,且函数体相同的情况。如果
个数不同,则不能用函数模板。

 

posted @ 2018-06-28 20:48  小念之歌  阅读(408)  评论(0编辑  收藏  举报