版权声明: 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.特化并不是重载,