1. 程式人生 > >模板函式與模板類

模板函式與模板類

前言:通常我們想要比較不同資料型別的時候不得不定義兩種不同的函式來表示區分,為了能精簡程式碼和避免強型別的嚴格性和靈活性的衝突,我們就需要用到模板去改善這種情況。

一、函式模板

//函式模版的隱式例項化
  #include <iostream>
  using namespace std;
  
  template <class T>
  T Max(T x, T y);    //函式模版的申明
  
 int main()
{
     int intX = 1, intY = 2;
     double dblX = 3.9, dblY = 2.9;
     cout << Max(intX, intY) << endl;    //實參為int型,生成int型模板函式,並對第二個引數進行檢查
    //或者cout << Max<int>(intX, intY) << endl;
     cout << Max(dblX, dblY) << endl;    //實參為double型,生成double型模板函式,並對第二個引數進行檢查
     //或者cout << Max<double>(dblX, dblY) << endl;
     cout << Max(dblY,intX) << endl; //模板函式做不到兩個引數型別不一致還可以比較

     return 0;
 }
 
 template <class T>
 T Max(T x, T y)        //函式模版的實現
 {
     return (x > y ? x : y);
 }、

正常函式模板:

template <typename T1, typename T2, Typename T3>

T1 sum(T2, T3)

{

T1 nres;

cout<<"執行相應de"的操作"<<endl;

retuen nres;

}

顯示呼叫:auto val= sum<long long>(i, lng); //返回值型別:long long,形參型別:T2=decltype(i) , T3=decltype(lng)

或者:auto val1= sum<long long, int, long>(i, lng); //返回值型別:long long,形參型別:T2=int , T3=long

尾置函式模板:返回序列中元素型別的引用

template <typename It>

auto fcn (It beg, It end)->decltype(*beg)

{

return *beg;//返回序列中元素型別的引用

}

呼叫:vector<int > ci={1,2,3,4,5};

Blob<string> ca={"hi","bye"};

auto &i=fcn(vi.begin(),vi.end()); //fcn返回int&

auto &s=fcn(ca.begin(),ca.end()); //fcn返回string&

尾置函式模板:返回序列中一個函式的引用

template <typename It>

auto fcn (It beg, It end)->typename remove_referance<decltype(*beg)>::type

{

return *beg;//返回序列中元素的拷貝

}

函式指標和實參的推斷:

template <typename T> int compare(const T&, const T&);

void func(int(*)(const string&, const string&));

呼叫:func(compare <int>);//指定實參型別

從右值引用推斷型別

template <typename T> void f3(T&&);

f3(43);

引用摺疊:建立一個引用的引用,這些引用形成了“摺疊”,引用因此會摺疊為左值引用型別

規則:

1.如果一個函式的引數是一個指向函式模板型別引數的右值引用,則它可以被繫結為一個左值

2.如果一個函式的引數是一個指向函式模板型別引數的左值引用,則它可以被繫結為一個左值

void f(int v1, int &v2)
{
    cout << "" << ++v2 << endl;
}

template <typename F, typename T1, typename T2>
void flip1(F f, T1 &&t1, T2 &&t2)//引用摺疊,保留原引數t1的左值型別
{
    f(t2, t1);//t1是左值
}

呼叫:flip1(f, j, 42);

std::move語義:可傳遞給move一個左值或者右值,最終都會得到一個右值

完美轉發:保留原資料型別

void f1(int &&v1, int &v2)
{
    cout << v1 << "" << ++v2 << endl;
}

template <typename F, typename T1, typename T2>
void flip2(F f, T1 &&t1, T2 &&t2)//引用摺疊
{
    f1(std::forward<T2>(t2), std::forward<T1>(t1));//保留t1,t2的右值型別
}

呼叫:flip2(f, j, 42);

可變引數模板

template <typename T, typename ...args> void foo(const T &t, const args&... res)
{
    cout << sizeof...(args) << endl;// sizeof...(args)獲取包中有多少個可變引數
}

呼叫:foo(i,j,13,4213,44);

利用可變引數模板來列印值

template <typename T> ostream & _print(ostream &os, const T &t)
{
    return os << t;//列印最後一個元素
}

template <typename T, typename ...args> ostream &_print(ostream &os,const T &t, const args&... res)
{
    os << t << ",";
    return _print(os, res...);//遞迴呼叫列印值
}

呼叫:

_print(cout, i, j, 132);

_print(cout, i, j, 132, 42, 34);

模板特例化

原始模板函式

template <typename T>
int compare(const T &v1, const T &v2)
{
	if (less<T>()(v1, v2))
	{
		return -1;
	}

	if (less<T>()(v2, v1))
	{
		return 1;
	}
	return 0;
}

特例化函式

template<>
int compare(const char* const &v1, const char* const&v2)
{
	return strcmp(v1, v2);
}

呼叫:

const char *p1 = "hi";
const char *p2 = "mom";
compare(p1, p2);

二、模板類

#include <iostream>
   using namespace std;
   
   #define MaxSize 10
   
   template <class T>
   class CStack
   {
   private:
      T data[MaxSize];
      int top;
  public:
      CStack():top(-1)
      {
      }
      void Push(void);
      void Pop(void);
      bool ifEmpty()
     {
          if(top == -1)
              return true;
          else
              return false;
      }
      bool ifFull()
      {
          if(top == MaxSize-1)
              return true;
          else
              return false;
      }
      T getTop(void)
      {
          if(ifEmpty())
          {
              cout<<"棧為空,不能取棧頂!"<<endl;
              return -1;
          }
          return this->data[top];
      }
  };
  
  template <class T>
  void CStack<T>::Push(void)
  {
      if(ifFull())
      {
          cout<<"棧已滿,不能入棧!"<<endl;
          return ;
      }
      T a;
      cin>>a;
      this->data[++top] = a;
      cout<<"元素"<<a<<"入棧!"<<endl;
  }
  
  template <class T>
  void CStack<T>::Pop(void)
  {
      if(ifEmpty())
      {
          cout<<"棧為空,不能出棧!"<<endl;
          return ;
      }
      T temp = this->data[top--];
      cout<<"元素"<<temp<<"出棧!"<<endl;
  }
  
  
  int main()
  {
      CStack<int> s1;    //可以自己更換資料型別int
      int i;
      do
      {
          cout<<"\t===============================\n";
          cout<<"\t*********順序棧類模板**********\n";
          cout<<"\t           1.入棧              \n";
          cout<<"\t           2.出棧              \n";
          cout<<"\t           3.取棧頂            \n";
          cout<<"\t           0.退出              \n";
          cout<<"\t*******************************\n";
          cout<<"\t===============================\n";
          do
          {
              cout<<"\tplease input your operator:";
              cin>>i;
              system("cls");
          }while(i!=1 && i!=2 && i!=3 && i!=0);
          switch(i)
          {
          case 1:
              s1.Push();
              system("pause");
              system("cls");
              break;
          case 2:
              s1.Pop();
              system("pause");
             system("cls");
             break;
          case 3:
             if(-1 == s1.getTop())
             {
                 system("pause");
                 system("cls");
                 break;
             }
             else
                 cout<<"棧頂元素為:"<<s1.getTop()<<endl;
             system("pause");
             system("cls");
             break;
         }
     }while(i != 0);
 }