函数模版 特化 模版指针

版权声明: https://blog.csdn.net/dashoumeixi/article/details/82933312

函数特化在下面做了大量的补充;

类模版

 函数模版与类模版的一个不同点是:

类模版如 :
template <typename T> 
class A{}; 
那么 A<int> 或 A<double> 是一个类;  即A是模版,A后面带着<XXX>则是一个类;

函数模版如:
template <typename T>
T compare(const T &a, const T& b)
{
    return T();
};
那么compare<int> 生成compare(const int&,const int&);
compare<double>  -> compare(const double &, const double&);

compare后的<> 只决定了生成的函数版本;

这个区别在看类和函数2个模版的时候需要注意
/*
    func.h
    第一个模版
    模版只有当使用时,编译器才会实例化,即生成代码;
    compare(1,0) 生成一个函数 : compare(const int &a ,const int &b);
    compare(1.0,2.0) 生成一个重载: compare(const double &, const double&);
    这种行为称为实例化;
*/
template <typename T> //模版头 . T是类型参数(int,double,short ... )
T compare(const T & a, const T & b)
{
    if(a >=b)
        return a;
    return b;
}

//main.cpp
//第一种方式: 隐式实例化,由编译器通过形参来确定类型

compare(2,3) ; // 函数模版可以由编译器通过参数类型推断出 T 的类型, 也可以compare<int>(2,3);

//第二种:
compare<int>(1,1); //这称为显示实例化 ,生成的函数与上面一样: int compare(const int &, const int&);



/*
    func.h
    函数模版重载;
    函数可以重载, 函数模版也可以重载;
    一个小例子, 不写实现了;
    与函数模版的重载一样, 参数不一样即可;
    与上面的T compare(const T & a, const T & b) 重载
*/
template <typename T>
T compare(T &a, T &b)
{
}







/*
    func.h
    模版的非类型形参;
    这个例子对引用数组不熟悉的可以略过;


    与上面不同的是 , template <> 内部并不是类型 .而是数组长度
    p1与p2 都是引用数组;
    对引用数组额外介绍一些:如有char arr[3];
    与指针指向整个数组的形式相似 : const char (*p)[3] = arr ;
    当然引用数组还有另一种形式: const char *const &p = arr; 相当于引用arr 地址;
    需要注意的是:
    **如果形参是一个引用, 实参是数组,则形参指向的是数组的类型,即带长度的数组;
    ** 例如, 上面的char arr[3]; 如果形参是引用,则其类型是: char [3] 或者 char (*)[3];
    ** 补充:
    ** template <typename T>
    ** void func_ref(const T &t1, const T& t2);
    ** 在使用的时候 func_ref(arr,arr); 此时 T 的类型是const int [3]
    ** 生成的函数原型是: func_ref(const int (&t1)[3], const int(&t2)[3]);
*/
#include <cstring>
template <int len1, int len2>
int compare(const char (&p1)[len1], const char(&p2)[len2])
{
    return strcmp(p1,p2);
}
//显示实例化的例子如下:
/*
  一般情况下直接调用:
  compare(1,1);  即可 , 因为编译器能自动推断出来.
  显示实例化的意思是 也可以这么用:
  compare<long,long>(1,1) ; 即生成了一个long compare(const long&,const long&);

  具体说明一下
  下面的模版有3个参数;
 */
template < typename ReturnType,typename T, typename U>
ReturnType compare(const T &a, const U &b)
{
    std::cout <<typeid(a).name() << "," << typeid(b).name() << std::endl;
    return ReturnType();
}
 /*
     * main.cpp
     *
     由于ReturnType 没有实参,编译器无法直接推断出来,所以需要在<>内写上返回类型
     而 T,U 由编译器做出决定, 当然也可以自己写
    */
    compare<long>(123,123);  //相当于 compare<long,int,int>(123,123);
    compare<double,int , short>(100,10);//也可以这样,显示制定了类型
/*
 让函数模版实例化的方式:
 1.声明式的:让编译器生成一个用于char类型的Swap; 下面代码说明
 2.同样的也可以在main中使用Swap('a','b');
 3.也可以这样main中:Swap<char>('a','b');
 以上3种方式都可以让编译器生成一份用于char的Swap函数.
 需要注意的是第一种声明式的方式
 */

/*
    补充一个函数实例化的声明式方式;
    请记住,所有的模版函数不使用是不生成代码的;
    上面所有摸板函数的实例化都是在使用时:
        compare(1,2) 生成 -> int compare(const int&,const int&);
    当你想在一开始就让编译器生成一个某类型的函数时.

    可以这么做 : template 后面加函数原型;
    template void Swap(const char&,const char&);
    或者template void Swap<char>(const char&,const char&);
    这样就指示编译器一开始就生成一个函数应用于char的Swap函数
*/
template <typename T>
void Swap(const T& a, const T& b)
{
    using std::cout;
    using std::endl;
    cout << typeid(a).name() << "," << typeid(b).name() << endl;
}
template void Swap<char>(const char&,const char&);

函数指针指向函数模版:

/*
     如有以下指针 p_func 指向一个模版函数.
     拿第一个模版作为例子 : 
     template <typename T>
     T compare(const T&,const T&);

     指针函数参数 const int &, 确定了T的类型. 所以p_func 指向的是 compare<int>;
    compare<int> ==> 
                    编译器将生成 int compare(const int &, const int &);
    */
    int (*p_func)(const int &,const int&) = compare; // 或者compare<int>

函数模版的具体化(特化):

叨叨絮絮一下 , 请现在先搞清楚函数模版的实例化,上面所有的函数模版例子都是由编译器实例化,即由编译器生成相应的函数代码,而特化从本质上来说就是我们自己写函数模版的实例化代码;

总之一句话,特化就是由我们自己编写的实例;

/*
    上面已经说过了函数模版重载,就像函数重载一样;
    现在说一下函数特化(具体化);
    上面的所有模版实例都有编译器替我们生成一个个函数,
    特化是由我们自己提供实例函数,让编译器别干涉生成了;
    请注意特化只能对某个函数模版进行特化.
    如果你有重载的多个函数模版,那么一个特化只能对其中一个函数模版进行特化;
    请下面的例子;
*/
/*
 函数模版;
 这个模版无法对const char*类型的字符串进行比较, 里面只用了 >= 进行比较;
 所以必须进行修改,此时可以用到特化.即对这个模版进行特殊处理;

 !!!!需要注意的是特化不是重载!!!!

 ***特化是对某个模版的所有模版参数提供实参
 ***换句话也可以这么说, 特化是在本质上我们接管了编译器的工作;
 *** 即特化是这个模版的一个实例,这个特化的实例函数由我们自己编写

*/
template <typename T>
int compare(const T& a, const T&  b)
{
    if(a >= b)
        return a;
    return b;
}


//第一个例子:
template <> //摸板头 , 对int 类型进行特化;
int compare(const int & a, const int & b)
{
    std::cout << "compare(const int & a, const int & b)" << std::endl;
}


//第二个例子: 对const char * 特化, 注意:所有参数由我们自己提供,函数模版没有部分特化,类模版有
template <> // <>里面为空,原模版的所有参数都由自己提供
int compare(const char * const & a, const char * const &b)
{
    return strcmp(a,b);
}
//main.cpp
    /*
      此时这个函数的实例化.由我们自己提供,编译器将不生成代码.
      这2个调用将使用我们自己提供的特化版本;
      当然如果你使用了compare(1.0,5.0); 由于并没有特化版本,
      此时编译器将生成一个;
     */
    compare(1,2); //也可以调用 compare<int>(1,2);
    const char * p1 = "123";
    const char * p2 = "456";
    compare(p1,p2); // 调用 compare(const char* const &,const char* const &);
/*
 这个是函数模版重载;
 请注意重载是重载,特化是特化.
 特化是对某1个函数模版进行的实例化
*/
template <typename T , typename U>
int compare(const T & a, const U & b)
{
    std::cout << "Im overloadddd . int compare(T & a, U & b)"    << std::endl;
}

/*
    这个特化是对上面的重载模版进行特化
    一定要分清特化与重载的区别;
*/
template <>
int compare(const int & a, const double & b)
{
    std::cout << "int compare(const int & a, const double & b)"    << std::endl;
}


//main.cpp
int main()
{
    compare(1,2.0); //或者compare<int,double>(1,2.0);将调用我们自己的特化;
    compare(1,"hi"); //编译器生成了一个int compare(const int & a, const char& b);
return 0;
}

最后总结一下特化(具体化):

1.特化就是我们自己提供的一个实例化;意思是编译器你别生成了,直接用我们提供的即可;

2.特化是对某1个函数模版进行特化.

3.特化并不是重载,

猜你喜欢

转载自blog.csdn.net/dashoumeixi/article/details/82933312