日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學無先后,達者為師

網站首頁 編程語言 正文

C++ 函數模板的重載與實參推斷

作者:weixin_45767431 更新時間: 2022-10-29 編程語言

? ? 結合網上的資料,對函數模板的重載與實參推斷做一個總結。

函數模板的重載

? 當需要對不同的類型使用同一種算法時,為了避免定義多個功能重復的函數,可以使用模板。然而,并非所有的類型都使用同一種算法,有些特定的類型需要單獨處理,為了滿足這種需求,C++允許對函數模板進行重載。

? 例如,當交換基本類型和交換兩個數組時,雖然功能都是交換,但是使用的方法卻不相同,交換兩個數組唯一的辦法就是逐個交換所有的數組元素。

template<class T> void Swap(T &a, T &b){
    T temp = a;
    a = b;
    b = temp;
}
template<typename T> void Swap(T a[], T b[], int len){
    T temp;
    for(int i=0; i<len; i++){
        temp = a[i];
        a[i] = b[i];
        b[i] = temp;
    }
}

函數模板的實參

? 在使用類模板創建對象時,需要顯式的指明實參,例如:

template<typename T1, typename T2> class Point;
Point<int, int> p1(10, 20);  //在棧上創建對象
Point<char*, char*> *p = new Point<char*, char*>("東京180度", "北緯210度");  //在堆上創建對象

對于函數模板,調用函數時可以不顯式的指明實參,編譯器會自動推導出T的類型,例如:

//函數聲明
template<typename T> void Swap(T &a, T &b);
//函數調用
int n1 = 100, n2 = 200;
Swap(n1, n2);
float f1 = 12.5, f2 = 56.93;
Swap(f1, f2);

模板實參推斷過程中的類型轉換

普通函數調用時的類型轉換

  • 算數轉換:例如 int 轉換為 float,char 轉換為 int,double 轉換為 int 等。
  • 派生類向基類的轉換:也就是向上轉型,
  • const 轉換:也即將非 const 類型轉換為?const 類型,例如將 char * 轉換為 const char *。
  • 數組或函數指針轉換:如果函數形參不是引用類型,那么數組名會轉換為數組指針,函數名也會轉換為函數指針。
  • 用戶自定的類型轉換。

例如:

void func1(int n, float f);
void func2(int *arr, const char *str);
int nums[5];
char *url = "http://c.biancheng.net";
func1(12.5, 45);
func2(nums, url);

? 對于 func1(),12.5 會從double轉換為int,45 會從int轉換為float;對于 func2(),nums 會從int [5]轉換為int *,url 會從char *轉換為const char *

函數模板調用時的類型轉換

? 對于函數模板,類型轉換收到了更多的限制,僅能進行[const 轉換]和[數組或函數指針轉換],其他都不能應用于函數模板。

template<typename T> void func1(T a, T b);
template<typename T> void func2(T *buffer);
template<typename T> void func3(const T &stu);
template<typename T> void func4(T a);
template<typename T> void func5(T &a);

int name[20];
Student stu1("張華", 20, 96.5);  //創建一個Student類型的對象
func1(12.5, 30);  //Error
func2(name);  //name的類型從 int [20] 換轉換為 int *,所以 T 的真實類型為 int
func3(stu1);  //非const轉換為const,T 的真實類型為 Student
func4(name);  //name的類型從 int [20] 換轉換為 int *,所以 T 的真實類型為 int *
func5(name);  //name的類型依然為 int [20],不會轉換為 int *,所以 T 的真實類型為 int [20]

可以發現,當函數形參是引用類型時,數組不會轉換為指針。

template<typename T> void func(T &a, T &b);

int str1[20];
int str2[10];
func(str1, str2);

? 由于str1、str2的類型分別為int [20]和int [10],在函數調用過程中又不會轉換為指針,所以編譯器不知道應該將T實例化為int [20]還是int [10],導致調用失敗

為函數模板顯式地指明實參

? 下面是一個實參推斷失敗的例子:

template<typename T1, typename T2> void func(T1 a){
    T2 b;
}
func(10);  //函數調用

func()有兩個類型參數,分別是T1和T2,但是編譯器只能推斷出T1,不能推斷出T2,調用失敗

? 顯示指明的模板實參會按照從左到右的順序與對應的模板參數匹配:第一個實參與第一個模板參數匹配,第二個實參與第二個模板參數匹配,只有尾部(最右)的類型參數的實參可以省略,而且前提是它們可以從傳遞給函數的實參中推斷出來。 例如:

template<typename T1, typename T2> void func(T2 a){
    T1 b;
}
//函數調用
func<int>(10);  //省略 T2 的類型
func<int, int>(20);  //指明 T1、T2 的類型

顯式的指明實參時可以應用正常的類型轉換

? 函數模板僅能進行[ const 轉換 ]和[ 數組或函數指針轉換 ]兩種形式的類型轉換,但是當我們顯式的指明類型參數的實參時,就可以使用正常的類型轉換了。例如:

template<typename T> void func(T a, T b);
func(10, 23.5);  //Error
func<float>(20, 93.7);  //Correct

? 在第二種調用形式中,我們已經顯式地指明了T的類型為float,編譯器不會再為T的類型到底是int還是double而糾結了,所以可以從容地使用正常地類型轉換了。

原文鏈接:https://blog.csdn.net/weixin_45767431/article/details/127574432

欄目分類
最近更新