当前位置 博文首页 > 文章内容

    C++实现模板中的非类型参数的方法

    作者:shunshunshun18 栏目:未分类 时间:2021-03-04 14:43:39

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    非类型模板参看,顾名思义,模板参数不限定于类型,普通值也可作为模板参数。在基于类型的模板中,模板实例化时所依赖的是某一类型的模板参数,你定义了一些模板参数(template<typename T>)未加确定的代码,直到模板被实例化这些参数细节才真正被确定。而非类型模板参数,面对的未加确定的参数细节是指(value),而非类型。当要使用基于值的模板时,你必须显式地指定这些值,模板方可被实例化。

    在函数模板中使用非类型参数

    #include<iostream>
    using namespace std;
    //在函数模板中使用非类型参数
    template<class T>void Swap(T &a, T &b);
    template<typename T, unsigned N>void Swap(T (&a)[N],T (&b)[N]);
    
    template<typename T, unsigned N>void printArray(T (&arr)[N]);
    
    int main(){
     int m = 10, n = 90;
     Swap(m,n);
     cout << "m = " << m << ", n = " << n << endl;
    
     int a[5] = { 1, 2, 3, 4, 5 };
     int b[5] = { 10, 20, 30, 40, 50 };
     Swap(a, b);
     printArray(a);
     printArray(b);
     return 0;
    
    }
    
    template<class T> void Swap(T &a,T &b){
     T temp = a;
     a = b;
     b = temp;
    }
    
    template<class T, unsigned N> void Swap(T (&a)[N],T (&b)[N]){
     T temp;
     for (int i = 0; i < N;i++){
     temp = a[i]; 
     a[i] = b[i];
     b[i] = temp;
     }
    }
    
    template<typename T, unsigned N>void printArray(T (&arr)[N]){
     for (int i = 0; i < N;i++){
     if (i == N-1){
      cout << arr[i] << endl;
     }
     else{
      cout << arr[i] << ", ";
     }
     }
    }

    在类模板中使用非类型参数

    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    using namespace std;
    
    //动态数组实现,在类模板中使用非类型参数
    template<typename T,int N>
    class Array{
    public:
     Array();
     ~Array();
    public:
     T & operator[](int i);//重载下标运算符
     int length() const{ return m_length; }//获取数组长度
     bool capacity(int n);//是否可改变数组容量
    private:
     int m_length;//数组当前长度
     int m_capacity;//当前内存容量
     T *m_p;//指向数组内存的指针
    };
    
    template<typename T,int N>
    Array<T, N>::Array(){
     m_p = new T[N];
     m_capacity = m_length = N;
    }
    
    template<typename T,int N>
    Array<T, N>::~Array(){
     delete[] m_p;
    }
    
    template<typename T,int N>
    T & Array<T, N>::operator[](int i){
     if (i<0||i>=m_length){
     cout << "Exception:Array index out of bounds!" << endl;
     }
     return m_p[i];
    }
    
    template<typename T,int N>
    bool Array<T, N>:: capacity(int n){
     if (n>0){
     int len = m_length + n;
     if (len<=m_capacity){
      m_length = len;
      return true;
     }
     else{
      T *pTemp = new T[m_length + 2 * n*sizeof(T)];
      if (NULL==pTemp){
      cout << "Exception: Failed to allocate memory!";
      return false;
      }
      else{ 
      memcpy(pTemp,m_p,m_length*sizeof(T));
      delete[] m_p;
      m_p = pTemp;
      m_capacity = m_length = len;
      }
     }
     }
     else{
     int len = m_length - abs(n);
     if (len<0){
      cout << "Exception:Array length is too small!" << endl;
      return false;
     }
     else{
      m_length = len;
      return true;
     }
     }
    }
    
    int main(){
     Array<int, 5> arr;
    
     for (int i = 0, len = arr.length(); i < len;i++){
     arr[i] = 2 * i;
     }
    
     cout << "first print:" << endl;
     for (int i = 0, len = arr.length(); i < len;i++){
     cout << arr[i] << " ";
     }
     cout << endl;
    
     //扩大容量为增加的元素赋值
     arr.capacity(8);
     for (int i = 5, len = arr.length(); i < len;i++){
     arr[i] = 2 * i;
     }
    
     cout << endl;
     cout << "second print:" << endl;
     for (int i = 0, len = arr.length(); i < len;i++){
     cout << arr[i] << " ";
     }
     cout << endl;
    
     arr.capacity(-4);
     cout << "third print: " << endl;
     for (int i = 0, len = arr.length(); i < len; i++){
     cout << arr[i] << " ";
     }
     cout << endl;
    
     return 0;
    }

    非类型模板参数的限制

    非类型模板参数是有类型限制的。一般而言,它可以是常整数(包括enum枚举类型)或者指向外部链接对象的指针。

    浮点数和类对象(class-type)不允许作为非类型模板参数:

    template<double VAL>      // ERROR: 浮点数不可作为非类型模板参数
    double process(double v)
    {
      return v * VAL;
    }
    
    template<std::string name>   // ERROR:类对象不能作为非类型模板参数
    class MyClass
    {}
    
    
    稍作变通,我们即可使编译通过:
    
    template<double* PVAL>
    double process(const double& x)
    {
      return x * (*PVAL);
    }
    
    template<const char* name>
    class MyClass
    {
      ...
    }
    
    

    这样可顺利通过编译,但如果想在当前文件中使用这两个模板,还需要动一些手脚:

    double val = 10;
    double res = process<&val>(20);   // ERROR: 表达式必须含有常量值
    
    MyClass<"hello"> x;         // ERROR: 模板参数不能引用非外部实体
    
    const char* s = "hello";
    MyClass<s> x;            // ERROR: 表达式必须含有常量值
    
    

    这里就点出另外一点注意事项,也就是非类型模板参数的限制,非类型模板参数可以是指针,但该指针必须指向外部链接对象,还记得在A.cpp中如何引用B.cpp中的全局变量吗,在A.hpp中使用extern关键字对外部变量加以引用。

    // B.cpp
    double val = 3.14159265;
    char str[] = "hello";
    
    
    // A.hpp
    extern double val;
    extern char str[];
    
    
    // A.cpp
    #include "A.hpp"
    
    double res = process<&val>(10);
    MyClass<str> x;