函数模板

函数模板

通用的函数描述,通过泛型来定义函数。


template <typename AnyType>

void swap(AnyType &a, AnyType &b)

{

  AnyType temp = a;

  a = b;

  b = temp;

}

创建模板在函数原型前使用 template ;

模板并不创建任何函数,只是告诉编译器如何定义函数,当类型为int时,编译器将用int替换T,按照模板创建这样的函数。

#include<iostream>
using namespace std;

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

template <typename T>
void swap_(T a[], T b[], int n)  // 模板重载
{
    T temp ;
    for(int i =0;i<n;i++)
    {
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }

}
template <typename T>
void show(T a, T b)
{
    cout<<a<<","<<b<<endl;
}

int main()
{
    int a=1,b=2;
    swap_(a,b);  // 编译器将根据模板自动创建一个int的swap_函数
    show(a,b);  // 编译器将根据模板自动创建一个int的show函数
    char c = 'A', d = 'B';
    swap_(c, d);
    show(c,d);
    char s1[] = "abcd";
    char s2[] = "efgh";
    swap_(s1,s2,4);
    show(s1,s2);
    return 0;

}

显示具体化

  1. 对于给定函数名,可以有非模板函数,模板函数和显示具体化模板函数以及它们的重载版本。
  2. 显示具体行的原型和定义应以template<>开头,并通过名称来指出类型。
  3. 具体化优先于常规版本,而非模板函数优先于具体化和常规版本
struct job{
  int a;
  int b; 
};

void fun(job a);// 非模板函数
// 模板函数
template <typename T>
void fun(T a);

// 显示具体化函数
template<> void fun<job>(job a);  // <job>可省略

实例化和具体化

函数模板本身并不会生成函数定义,它只是用于生成函数定义的方案,编译器使用模板为特定类型生成函数定义时,得到的是模板实例。
函数调用时,编译器会根据实参类型隐式的实例化一个特定类型的模板实例

显示实例化

声明所需的种类用<>指示类型,并在声明前加上关键字template
template void fun <int> (int, int)
编译器将使用fun模板生成一个使用int类型的实例。即表示用swap模板生成int类型的函数定义。
显示具体化
template<> void fun(int, int);
template<> void fun(int, int);
显示具体化的意思是不使用模板来生成函数定义,而使用专门为int类型显示定义的函数定义。
在同一个文件偶然转换单元中使用同一种类型二的显示实例和显示具体化将出错

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

template<typename T>
T add(T a, T b)
{
    cout<<"实例化 T.name = "<< typeid(T).name()<<endl;
    return a+b;
}

template<> char* add(char*a, char*b)
{
    cout<<"显示具体化"<<endl;
    int len = strlen(a)+strlen(b);
    char * ptr = new char[len];
    strcpy(ptr,a);
    strcpy(ptr+strlen(a)-1, b);
    cout<<"*"<<ptr<<"*"<<endl;
    return ptr;

}

template int add<int>(int a,int b);  // 显示具体化只需声明

int main()
{
    int a=1, b=2;
    cout<<add(a,b)<<endl;
    cout<<add(3.1, 4.0)<<endl;
    cout<<add<double>(3, 4)<<endl; // 显示具体化
    char s1[] = "abcd";
    char s2[] = "efgh";
    cout<<add(s1, s2)<<endl;
    return 0;
}

decltype(c++11)

template<class T1, class T2>
void ft(T1 x, T2 y)
{
  ?type? xpy = x+y; // 不同类型的结果相加,xpy的类型未知
}

c++11提供的关键字decltype提供了解决方案。

int x;
decltype(x) y; // 让y的类型为x

decltype(x+y) xpy = x+y;  // decltype的参数可以是表达式

decltype(expression) var;

  1. 如果expression是一个没用括号括起来的标识符,则var的类型与该标识符的类型相同,包括const限定符
const double * p;
decltype(p) x; // x 的类型是 const double *
  1. 如果expression是函数调用,则var的类型与函数返回类型一致
decltype(func(3)) m; // m的类型和func的返回值类型一致,但并不会实际调用函数,编译器会查看函数原型来获取返回类型
  1. expression是一个左值,且是用括号括起来的标识符,则var是对应类型的引用。
double xx =1;
decltype((xx)) p = xx; // p是一个指向double的引用
decltype(xx) w = xx; // w是一个double
  1. 如果前面的条件都不满足则var的类型与expression相同
int j=3;
decltype(j+6) x; // x是int
decltype(100L) y; // y是long
int &k = j;
int &n = j;
decltype(k+n)  z; // z是int

后置返回类型

template<typename T1, typename T2>
?type? gt(T1 a, T1 b)  // 因为a和b的定义在后面无法通过decltype来获取返回值类型
{
   return a+b;
}

后置返回类型和关键字auto来解决。
auto gt(T1 a, T2 b) -> decltype(a+b)

#include<iostream>
using namespace std;

template<typename T1, typename T2>
auto add(T1 a, T2 b)-> decltype(a+b)
{
    return a+b;
}

int main()
{
    int a=3;
    double b = 4;
    cout<<add(a,b)<<endl;
    short c = 3;
    char d = 'A';
    cout<<add(c, d)<<endl;
    return 0;
}
posted @ 2022-06-16 22:33  店里最会撒谎白玉汤  阅读(37)  评论(0)    收藏  举报