c++ 模板

什么是模板?

模板是c++的一种特性,允许函数或者类(对象)通过泛型(generic types)的形式表现或者运行

模板可以使得函数或类在对应不同的类型(types)的时候正常工作,而无需为每一种类型分别写一份代码。

c++ 有两种类型的模板

1:函数模板(function tempalte):使用泛型参数的函数(function with generic parameters)

2:类模板(class template):使用泛型参数的类(class with generic parameters)

模板实例化

模板的声明(declaration)其实并未给出一个函数或者类的完全定义(definition),只是提供了一个函数或者类的语法框架(syntactical skeleton)

实例化是指从模板构建出一个真正的函数或者类的过程。用具体类型代替模板参数的过程叫做实例化;从而产生一个模板实例。

如果实例化一种类型,而该类型并不支持函数所使用的操作,那么就会导致一个编译错误

实例化有两种类型

1:显示实例化-在代码中明确指定要针对哪种类型进行实例化

2:隐式实例化-在首次使用时根据具体情况使用一种合适的类型进行实例化

函数模板编译(两次):

1:没有实例化之前,检查代码本身是否有语法错误。

2: 实例化期间,检查对模板代码的调用是否合法。

函数模板

什么是函数模板?

函数模板是参数化的一族函数(a famliy of functions)

通过函数模板,可以实例化一系类函数,这些函数都给予同一套模板框架,但是作用在不通类型的参数上

示例 :(针对不同的数据类型 比较两个数据的大小)

#include <iostream>
template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个 
inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义 
{
    return a>b?a:b;
}
int main()
{
    int a =1;
    int b =2;
    auto ret = max<int>(a,b);
    std::cout<<"int ret = "<<ret<<std::endl;
    double da=1;
    double db =2;
    auto ret1 = max(da,db);
    std::cout<<"double ret1 = "<<ret1<<std::endl;
    return 0;
}

参数推导

模板参数是由传递给模板函数的实参决定的

不允许自动类型转换:每个T必须严格匹配

#include <iostream>
template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个 
inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义 
{
    return a>b?a:b;
}
int main()
{
    int a =1;
    double b =2.0;
    //auto ret = max(a,b); //error 模板只有一种参数 但是这里传入了两种类型的参数
    //解决办法
    //用static_cast 强制转换参数类型使得 参数匹配
    auto ret1 = max(static_cast<double>(a),b);
    
    //显示指定T的类型
    auto ret2 =  max<double>(a,b);
   
    return 0;
}

参数不匹配报错

函数模板重载

#include <iostream>
template <typename T> //模板参数由关键字typename(也可以使用class) 定义 定义一个函数模板 返回两个数中数值大的那一个 
inline T max(const T &a,const T &b)//函数有两个参数 ,类型为定义 
{
    return a>b?a:b;
}

#include <iostream>
template <typename T> 

inline T max(const T &a,const T &b,const T &c)
{
   T temp;
   if(a<b)
   {
         temp = b;       
   }
   else
   {
        temp = a;
   }
   return temp >c?temp :c;

}

inline int max(const int &a,const int &b)
{
    return a>b?a:b;
}

template <typename T,typename T1=double>
inline T max(const T &a,const T1 &b)
{   
    std::cout<<"template <typename T,typename T1=double> "<<std::endl;
    return a>b?a:b;
}

int main()
{
   max(1,2,3);     // max(const T &a,const T &b,const T &c) max<int>
   max(1.0,2.3);     //max(const T &a,const T &b) max<double>
   max('a','b');    //max(const T &a,const T &b)  max<char>
   max(1,2);    //inline int max(const int &a,const int &b)
   max<>(1,2);    //max(const T &a,const T &b) max<int>
   max<int>(1,2);    //max(const T &a,const T &b) max<int>
   max('a',2);    //inline int max(const int &a,const int &b)
   return 0;
}

类模板

与函数模板类似,类也可以通过参数泛化,从而可以构建出一族不同的类实例(对象)

类模板实参可以是某一类型或常量(仅限int或enum)

示例

#include<iostream>
#include<vector>
/*********************************************************
*T可以是任意类型
*模板实参也可以是一个int或enum类型的常量 size_t实际是int类型
*n是编译时定义的常量
*n可以有默认值
*size_t类型的成员变量可以用n初始化
***********************************************************/
const std::size_t DefaultStackSize = 1024;
template <typename T,std::size_t n = DefaultStackSize>
class Stack
{
public:
    void Push(const T &element);
    int Pop(T &element);
    //int Top(T &element) const;
private:
    std::vector<T> m_Members;
    std::size_t m_mMaxSize = n; 
};

template <typename T,std::size_t nMaxSize>
void Stack<T,nMaxSize>::Push(const T &element)
{
    if(m_mMaxSize <= m_Members.size())
    {
        return;
    }
    m_Members.push_back(element);
}

template <typename T,std::size_t nMaxSize>
int Stack<T,nMaxSize>::Pop(T& element)
{
    if(m_Members.empty())
    {
        return -1;
    }
    element = m_Members.back();
    m_Members.pop_back();
    return 0;
}


int main()
{
    Stack<int> stack;
    Stack<int,100> stack1;
    for(int i =0;i<100;i++)
    {
        stack.Push(i);
    }
   int i;
   stack.Pop(i);
   std::cout<<i<<std::endl;
   stack.Pop(i);
   std::cout<<i<<std::endl;
   return 0;
}

类模板特化

允许对一个类模板的某些模板参数类型做特化

特化的作用和好处

对于某种特殊的类型,可能可以做些特别的优化或提供不同的实现

避免在实例化的时候引起一些可能不好的行为

特化一个类模板的时候也意味着需要特化其所有参数化的成员函数

示例:

#include<iostream>
#include<vector>
/*********************************************************
*T可以是任意类型
*模板实参也可以是一个int或enum类型的常量 size_t实际是int类型
*n是编译时定义的常量
*n可以有默认值
*size_t类型的成员变量可以用n初始化
***********************************************************/
const std::size_t DefaultStackSize = 1024;
template <typename T,std::size_t n = DefaultStackSize>
class Stack
{
public:
    void Push(const T &element);
    int Pop(T &element);
    //int Top(T &element) const;
private:
    std::vector<T> m_Members;
    std::size_t m_mMaxSize = n; 
};

template <typename T,std::size_t nMaxSize>
void Stack<T,nMaxSize>::Push(const T &element)
{
    if(m_mMaxSize <= m_Members.size())
    {
        return;
    }
    m_Members.push_back(element);
}

template <typename T,std::size_t nMaxSize>
int Stack<T,nMaxSize>::Pop(T& element)
{
    if(m_Members.empty())
    {
        return -1;
    }
    element = m_Members.back();
    m_Members.pop_back();
    return 0;
}
template <>
class Stack<std::string>
{
public:
    void Push(const T &element);
    int Pop(T &element);
    //int Top(T &element) const;
private:
    std::list<string> m_Members;
    std::size_t m_mMaxSize; 
};

int main()
{
    Stack<int> stack;
    Stack<int,100> stack1;
    for(int i =0;i<100;i++)
    {
        stack.Push(i);
    }
   int i;
   stack.Pop(i);
   std::cout<<i<<std::endl;
   stack.Pop(i);
   std::cout<<i<<std::endl;
   return 0;
}

类模板也可以偏特化 

template <typename T1,typename T2> 
class MyClass
{
};

//偏特化
template <typename T>
class MyClass<T,T>
{};

template <typename T1,typename T2>
class MyClass<T1*,T2*>
{};


template <typename T>
class MyClass<T,int>
{};


  • 14
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值