函数模板

泛型编程:不考虑具体数据类型的编程

函数模板:可用不同参数类型进行调用的函数(类型可以被参数化)

语法:

template < typename T >   // T 泛指任意的数据类型
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

 

语法规则:template 关键字用于声明开始进行泛型编程(声明一个模板)。typaname 用于声明泛指类型。

调用规则:自动类型推导调用(根据函数调用时实参的类型设置T的类型)--> Swap(a,b)。具体类型显示调用(函数调用时指定T的类型)--> Swap<float>(a,b)。

函数模板原理:函数模板是个模子,编译器通过模板和具体参数类型产生不同的函数。编译器会进行两次编译,第一次检测模板代码,第二次检测加参数后的具体函数代码。 

 注意:模板本身不是函数,模板本身不允许隐式类型的转换。自动推导时:必须参数匹配。显示指定时:能进行隐式类型转换。

 

#include <iostream>
#include <string>

using namespace std;

class Test
{
    Test(const Test&);  // 拷贝构造函数为是由函数,Test类无法进行拷贝构造
public:
    Test()
    {}
};

template < typename T >   // 第一次编译:编译时进行模板的检查
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

typedef void(FuncI)(int&, int&);
typedef void(FuncD)(double&, double&);
typedef void(FuncT)(Test&, Test&);

int main()
{
    FuncI* pi = Swap;    // 编译器自动推导 T 为 int        1.自动类型推导        2.产生一个函数     3.将函数地址赋给pi
    FuncD* pd = Swap;    // 编译器自动推导 T 为 double
    FuncT* pt = Swap;    // error 第二次编译时:编译器自动推导 T 为 Test,并生成一个参数为Test函数,但是函数内部有拷贝,出错
    
    cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
    cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
    cout << "pt = " << reinterpret_cast<void*>(pt) << endl;
    
    return 0;
}

 

 

多参函数模板:

语法:

template <typename T1,typename T2,typename T3>
T1 Add(T2 a,T3 b)
{
    return static_cast<T1>(a+b);
}
int ret = Add<int, float, double>(0.5, 0.8); // 函数在此才被创建

 

 注意:多参函数模板无法推导返回值类型,所以返回值类型必须显示指定。

    可以从左向右指定参数类型。

       推荐将返回值参数作为第一个类型参数来声明。

    // T1 = int, T2 = double, T3 = double
    int r1 = Add<int>(0.5, 0.8);            // T1显式指定返回值类型 (部分显示指定类型参数),T2,T3由编译器自动推导
    // T1 = double, T2 = float, T3 = double
    double r2 = Add<double, float>(0.5, 0.8);
    // T1 = float, T2 = float, T3 = float
    float r3 = Add<float, float, float>(0.5, 0.8);

 

 

 函数模板与被重载时:

1. C++编译器优先考虑重载普通函数。

2. 空实参列表模板限定编译器重载时只匹配模板Max<>(a,b)。

#include <iostream>
#include <string>

using namespace std;


template < typename T >   //
T Max(T a, T b)
{
    cout << "T Max(T a, T b)" << endl;  
    return a > b ? a : b;
}

int Max(int a, int b)      //函数重载函数模板
{
    cout << "int Max(int a, int b)" << endl;    
    return a > b ? a : b;
}

template < typename T >    //函数模板重载函数
T Max(T a, T b, T c)
{
    cout << "T Max(T a, T b, T c)" << endl;    
    return Max(Max(a, b), c);
}

int main()
{
    int a = 1;
    int b = 2;  // 进行重载时的选择根据参数类型,个数
    
    cout << Max(a, b) << endl;                   // 普通函数 Max(int, int)    
    cout << Max<>(a, b) << endl;                 // 只考虑函数模板 Max<int>(int, int)    
    cout << Max(3.0, 4.0) << endl;               // 函数模板 Max<double>(double, double)   
    cout << Max(5.0, 6.0, 7.0) << endl;          // 函数模板 Max<double>(double, double, double)    
    cout << Max('a', 100) << endl;               // 普通函数 Max(int, int)    
    return 0;
}

 

函数模板特化:特化就是模板的特殊形式,根据参数分为完全特化(参数类型完全确定),部分特化(参数类型相同)。

函数模板特化只支持函数模板的完全特化。

template <typename T>
void function(T a,T b)
{
  /* do something */
} template < > void function<type>(type a,type b) //函数模板完全特化 {
  /* do something */
}

 

函数特化遇上函数重载:

#include <iostream>
#include <string>

using namespace std;

template
< typename T >
bool function(T a, T b)   // 函数模板
{
  /* do something */
} template
< > bool function<double>(double a, double b) // 函数模板的完全特化 {
  /* do something */
}
bool function(double a, double b) // 全局函数对函数模板进行重载 {
  /* do something */
}
int main() { function( 1, 1 ); // 根据参数类型,调用函数模板 function( 0.001, 0.001 ); // 根据参数类型,优先调用重载的全局函数 function<>( 0.001, 0.001 ); // 使用 function<>() 时只考虑调用函数模板,根据参数选择完全特化 return 0; }

 

posted @ 2019-05-13 19:23  张不源  Views(455)  Comments(0Edit  收藏  举报