精华内容
参与话题
问答
  • 函数模板特化

    2016-12-03 21:11:00
    #include <iostream> template <typename T> ...//函数模板特化 template <> const char* max(const char* x, const char* y){ return strcmp(x, ...
    #include <iostream>
    template <typename T>
    T max(T x, T y)
    {
        return x > y ? x : y;
    }
    
    //函数模板特化
    template <>
    const char* max(const char* x, const char* y){
        return strcmp(x, y) > 0 ? x : y;
    }
    
    int main(){
        std::cout << max(1, 2);
        std::cout << max("hello", "world");
        return 0;
    }

     

    展开全文
  • 使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用) 当使用一个判断相等的模板函数时 template&...

    关于模板的特化

    函数的特化

    使用模板时会遇到一些特殊的类型需要特殊处理,不能直接使用当前的模板函数,所以此时我们就需要对该类型特化出一个模板函数(就是写出一个模板函数专门给该类型使用)

    当使用一个判断相等的模板函数时

    template<class T>
    bool Isequal(T& p1, T& p2){
    	return p1 == p2;
    }
    
    

    但是该模板函数在对于字符串进行比较时就不能使用了,对于字符串我们不能直接比较,因此直接特化出一个专门供字符串使用的模板参数

    template<> // 此处不添加类型模板,直接使用空即可
    bool Isequal<char*>(char*& p1, char*& p2){
    	return strcmp(p1, p2) == 0;
    }
    

    【注意】

    • 使用模板特化时,必须要先有基础的模板函数(就是上面第一个模板函数)

    • 使用特换模板函数时格式有要求:

      1.template 后直接跟<> 里面不用写类型
      2.函数名<特化类型>(特化类型 参数1, 特化类型 参数2 , …) 在函数名后跟<>其中写要特化的类型

    • 特化的函数的函数名,参数列表要和原基础的模板函数想相同,避免不必要的错误

    在实际使用中,为了实现简单,对于一些模板函数处理有问题的特殊类型,我们将其直接写出

    bool Isequal(char*& p1, char*& p2){
    	cout << "char2" << endl;
    	return strcmp(p1, p2) == 0;
    }
    
    • 当有可以直接匹配的函数时,即使有特化出的函数,都优先使用直接匹配的函数

    类的模板特化

    类的模板特化分为两种,一种是全特化,一种为偏特化

    • 全特化: 即将所有的模板类型都进行特化
    template <class T1, class T2>
    class Test{
    }
    
    //全特化
    template <>  //此处同函数模板的特化一样不用写内容
    class Test<int , char>{
        
    }
    
    • 偏特化:对于模板的类型做一些限制
    • 偏特化份为两种 一种是部分特化,一种是对于模板类型的进一步限制
    • 部分特化:就是只对函数模板的一部分模板类型进行特化
    template <class T1, class T2>
    class Test2{
    }
    
    //部分特化
    template <class T1>  //此处只需写未进行特化的模板类型,特化过的就不用写
    class Test2<T1 , char>{
        
    }
    
    • 对类型的范围的限制,主要的类型基础不变
    template <class T1, class T2>
    class Test2{
    }
    
    //对模板类型的范围做出一定的限制
    template <class T1 , class T2 >  //此处只需写未进行特化的模板类型
    class Test2<T1* , T2*>{
    }
    

    在调用时都将调用与自己的类型最相匹配的。

    展开全文
  • 一、模板特化介绍 template<class T1,class T2> class Test { private: T1 m_a; T2 m_b; public: Test() { cout << "T1 T2" << endl; } }; 上面是一段普通模板类的代码 ...

    一、模板特化介绍

    template<class T1,class T2>
    class Test
    {
    private:
    	T1 m_a;
    	T2 m_b;
    public:
    	Test()
    	{
    		cout << "T1 T2" << endl;
    	}
    };
    

    上面是一段普通模板类的代码

    1.1全特化

    template<>//全特化template中缺写
    class Test<char,int>
    {
    private:
    	char m_a;
    	int m_b;
    public:
    	Test()
    	{
    		cout << "char int" << endl;
    	}
    };
    

    1.2.偏特化

    template<class T1>//偏特化template缺掉要实例的那个类型
    class Test<T1, int>
    {
    private:
    	T1 m_a;
    	int m_b;
    public:
    	Test()
    	{
    		cout << "T1 int" << endl;
    	}
    };
    

    通过上面全特化和偏特化的代码可以看出:模板的全特化就是将模板的全部类型实例化,偏特化就是将模板的部分类型实例化。

    int main1()
    {
        Test<double,float> t1;
    	Test<char, int> t2;
    	Test<double, int> t3;
        system("pause");
        return 0;
    }
    

    在这里插入图片描述
    注意:
    1、特化必须针对一个已经存在的函数模板,不能单独存在。
    2、函数模板特化方式参考类模板特化

    二、函数模板特化和函数重载的比较

    template<class T1,class T2>
    void Fun(T1 a,T2 b)//模板函数
    {
    	cout << "模板函数" <<endl;
    }
    
    template<>//模板函数的全特化
    void Fun(char a, int b)
    {
    	cout << "全特化" << endl;
    }
    
    template<class T1>//模板函数的偏特化
    void Fun(T1 a, float b)
    {
    	cout << "偏特化" << endl;
    }
    
    
    void Fun(char a, float b)//模板函数的函数重载1
    {
    	cout << "函数重载1" << endl;
    }
    
    void Fun(char a, int b)//模板函数的函数重载2
    {
    	cout << "函数重载2" << endl;
    }
    
    
    int main()
    {
    	char char_tmp = 0;
    	int int_tmp = 0;
    	float float_tmp = 0;
    	Fun(float_tmp, int_tmp);
    	Fun(char_tmp, int_tmp);
    	Fun(int_tmp, float_tmp);
    	Fun(char_tmp, float_tmp);
    	Fun(char_tmp, int_tmp);
    
        system("pause");
        return 0;
    }
    

    在这里插入图片描述
    总结:
    1.传入类型匹配度越高调用优先级越高
    2.若传入类型对函数重载和模板函数的全特化一样高则优先调用函数重载
    3.模板函数(类)不存在,模板函数(类)特化就不存在,函数重载就不会。

    展开全文
  • 1、非类型模板参数 ** 模板参数分为 类型形参+非类型形参 类型形参: template<class T,typename container>; 非类型形参 1、template<class T,size_t N = 10> array<int,‘a’>,表示N = 97;...

    **

    1、非类型模板参数

    **
    模板参数分为 类型形参+非类型形参

    类型形参:
    template<class T,typename container>;
    非类型形参
    1、template<class T,size_t N = 10>
    array<int,‘a’>,表示N = 97;ascii值。
    2、template<class T,char c>
    long int short char都可以
    上边两个都可以作为非类型模板参数的值
    3、template<class T,double D>
    4、 template<class T, string s>
    浮点数、类对象 字符串 都不能做非类型模板参数的类型
    非类型的模板参数必须在编译期就能确认结果。

    **

    模板的特化

    **
    为什么使用模板?
    使用模板可以实现一些与类型无关的代码。
    模板特化的概念
    通常情况下,模板是可以实现一些与类型无关的代码的,但是对于特殊了类型会得到一些错误的结果。
    针对于上述情况,需要对模板进行一个特化。
    对于模板的特化 也就是 针对特殊类型所进行的特殊化实现。

    模板特化分为函数模板特化类模板特化

    **

    函数模板特化–处理了特殊类型char*

    **
    函数模板特化步骤:
    1、要先有一个基础的函数模板
    2、在关键字template后边加<>
    3、在函数名的后边加一个<>,<>里边放需要特化的类型
    4、函数的参数列表要与基础模板的参数类型相同。

    template<class T>1bool IsEqual(T& left, T& right) 
    {
       return left == right; 
    }
    //因为这个的话给T的参数就是char*,这个不是内置类型,是一种特殊类型,所以需要进行特化。
    template<>2bool IsEqual<char*>(char*& left, char*& right)34{
         if(strcmp(left, right) > 0)
         return true;
         return false;
     }
    //因为这个的话给T的参数就是char*,这个不是内置类型,是一种特殊类型,所以需要进行特化。
    void Test()
    {
       char* p1 = "hello";
       char* p2 = "world";//p1 != p2 在堆上,开辟两个空间
       if(IsEqual(p1, p2))
       cout<<p1<<endl;
       else
       cout<<p2<<endl; 
       char* p1 = "hello";
       char* p2 = "hello";//p1 = p2  在堆上,开辟一个空间存hello
       char arr1[] = {"abc"};
       char arr2[] = {"abc"};//arr1 != arr2;在栈上,开辟两个空间存abc
    }
    

    一般情况下,如果函数模板对于 不能处理的或者处理有误的类型,,为了实现简单一直都是将函数直接给出。

    bool IsEqual(char* left, char* right) 
    {
       if(strcmp(left, right) > 0)
       return true;
       return false; 
    }
    

    **

    类模板特化–全特化,偏特化

    **
    全特化
    全特化 将 类模板的 参数列表参数 全部确定化
    偏特化
    对模板参数 进一步进行条件限制设计的特化版本
    偏特化的两种表现形式
    1、将类模板中的参数一部分进行特化
    2、不仅仅指特化部分参数,针对模板参数更进一步进行条件设计

    template<class T1, class T2>//类模板
    class Data
    {
       public:
         Data() {cout<<"Data<T1, T2>" <<endl;}
       private:
         T1 _d1;
         T2 _d2;
    };
    
    template<>
    class Data<int, char> //类模板的全特化
    {
       public:
        Data() {cout<<"Data<int, char>" <<endl;}
       private:
        T1 _d1;
        T2 _d2;
    };
    
    template <class T1>//偏特化的第一种形式,部分参数进行特化1、
    class Data<T1, int> 
    {
       public:
         Data() {cout<<"Data<T1, int>" <<endl;}
       private:
         T1 _d1;
         int _d2;
    };
    template <typename T1, typename T2>//偏特化的第二种形式,偏特化为指针类型2、
    class Data <T1*, T2*>
    { 
       public:
         Data() {cout<<"Data<T1*, T2*>" <<endl;}
       private:
         T1 _d1;
         T2 _d2;
    };
    template <typename T1, typename T2>//偏特化的第二种形式,偏特化为引用类型2、
    class Data <T1&, T2&>
    {
        public:
         Data(const T1& d1, const T2& d2)
           : _d1(d1)
           , _d2(d2)
          {
             cout<<"Data<T1&, T2&>" <<endl;
           }
        private:
         const T1 & _d1;
         const T2 & _d2; 
     };  
    
    void TestVector()
    {
        Data<int, int> d1;// 调用基础的模板 
        Data<int , double> d2; // 调用基础的模板 
        Data<int, char> d2;//调用全特化
        Data<double , int> d1; // 调用特化的int版本--部分特化
        Data<int *, int*> d3; // 调用部分特化的指针版本
        Data<int&, int&> d4(1, 2); // 调用部分特化的引用版本
    }    
    

    **

    模板的分离编译–尽量不要将模板的声明与定义分开

    **
    什么是分离编译
    一个工程由若干个源文件共同实现,每个源文件单独编译程一个个的目标文件,然后将所有的目标文件链接起来构成单一的可执行文件的过程 称为分离编译模式。
    函数和类的声明写在.h文件中,将函数和类的定义写在.c文件中。
    为什么要分离编译?
    方便查看和维护。

    编译链接的过程
    func.c func.h main.c
    1、预处理
    //展开头文件
    //宏替换
    //去掉注释
    //条件编译 (if while 等等带有条件的语句)
    2、编译 func.i main.i
    //检查语法,生成汇编代码
    3、汇编func.o main.o
    //将汇编代码转为二进制代码
    4、链接 (当将模板的定义声明分开的时候,编译是可以通过的,但是在链接的时候会找main函数中实例化函数的地址,是找不到的,所以链接出问题
    //将目标文件链接在一起。

    ///分析以下代码–总结证明 模板的声明和定义不能分开

    // a.h
    template<class T> 
    T Add(const T& left, const T& right);
    // a.cpp 这个的a.o目标文件只有T类型的加法,,因为模板函数只有在使用时才会被实例化。当链接使用时要寻找加法实例化intdouble的地址,是找不到的。
    template<class T> 
    T Add(const T& left, const T& right) 
    {
        return left + right; 
    }
    // main.cpp
    #include"a.h"
    int main()
    {
       Add(1, 2);//在链接时,a.o的文件并没有实例化int的加法,main.o在链接时会链接不上
       Add(1.0, 2.0);//在链接时,a.o的文件并没有实例化double的加法,main.o在链接时会链接不上
       return 0; 
    }
    

    在这里插入图片描述
    解决方法
    1、将模板(模板函数模板类)的声明和定义放在一个文件中–方法1常用
    a.h文件

    //在a.h文件中,声明定义一块  
    //在a.cpp的文件中就不用定义了
    template<class T>
    void F2(const T& x)
    {
    	cout << "void F2(const T& x)" << endl;
    }
    

    2、模板定义的位置显示实例化–方法二,用多少个类型,就得声明多少个,不实用。–
    a.h文件

    template<class T>
    void F2(const T& x);
    

    在a.cpp文件

    template<class T>
    void F2(const T& x)
    {
    	cout << "void F2(const T& x)" << endl;
    }
    //解决编译链接错误   显示实例化
    template
    void F2<int>(const int& x);
    

    模板总结
    优点
    1、使用模板可以复用代码,节省资源
    2、迭代开发快
    3、c++模板标准库(STL)就是源于此实现的。
    4、代码的灵活度高
    缺点:
    1、模板会导致代码的膨胀度高,导致编译的时间过长
    2、当出现模板编译错误时,错误很难被定位。

    展开全文
  • 一、引子 考虑求两数较大值函数max(a,b) 对于a,b的不同类型,都有相同的处理形式: return a &lt; b ? b : a; ...(1)宏替换 #define max(a,b) ((a)&...(3)使用函数模板 二、模板 模板是...
  • 隐式实例化:通过编译器自己推演,判断出要实例化的类型 二 :特化=具体化类模板特化类模板template&lt;class T1,class T2&gt; class Date { public:Date() { cout &lt;&lt; "Dat...
  • C++函数模板特化与匹配学习笔记与参考 /* * @Descripttion: 函数模板练习 * 模板的特化可以认为有偏特化和全特化,但函数模板不支持偏特化,编译器无法通过,取而代之的实现是利用函数模板重载 * 而对于函数模板...
  • 头文件中有模板 // read the file content, returns errno if error happens. template<typename String> int readFile(StringArg filename, int maxSize, String* content, int64_t* fileSize = ...
  • 类模板,函数模板和模板函数特化都在头文件中。我在我的.cpp文件中 #include 头文件并编译链接工程。但是为了在整个工程中使用该库,我将头文件包含在 stdafx.h 中,结果出现特化模板函数的符号多重定义错误。我要...

空空如也

1 2 3 4 5 ... 20
收藏数 987
精华内容 394
关键字:

函数模板特化