【C++】 57_深刻理解函數模板

函數模板

  • 深刻理解函數模板ios

    • 編譯器從函數模板經過具體類型產生不一樣的函數
    • 編譯器會對函數模板進行兩次編譯編程

      • 對模板代碼自己進行編譯(語法檢查等)
      • 對參數替換後的代碼進行編譯(語法檢查等)

  • 注意事項函數

    • 函數模板自己不容許隱式類型轉換this

      • 自動推導類型時,必須嚴格匹配
      • 顯示類型指定時,可以進行隱式類型轉換

編程實驗: 函數模板的本質

#include <iostream>

using namespace std;

class 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
    FuncD* pd = Swap;    // 編譯器自動推導 T 爲 double
    FuncT* pt = Swap;    // 編譯器自動推導 T 爲 Test
    
    cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
    cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
    cout << "pt = " << reinterpret_cast<void*>(pt) << endl;

    return 0;
}
輸出:
pi = 0x80487e4
pd = 0x8048806
pt = 0x8048828

編譯器作了什麼?
FuncI* pi = Swap;  ==>
編譯器自動類型推導 ==> 生成對應的 Swap 函數 ==> 語法檢查合法後將 Swap 地址賦值給 pi
關於編譯器對函數模板進行的兩次編譯

第 1 次:對模板代碼自己進行的編譯檢查spa

#include <iostream>

using namespace std;

template < typename T >
void Swap(T& a, T& b)
{
    T c = a                      // 注意這裏!故意製造的語法錯誤
    a = b;
    b = c;
}

int main()
{
    return 0;
}
輸出:【g++】
test.cpp: In function ‘void Swap(T&, T&)’:
test.cpp:9: error: expected ‘,’ or ‘;’ before ‘a’

第 2 次:對參數替換後的代碼進行編譯檢查code

#include <iostream>

using namespace std;

class Test
{
private:
    Test(const Test& obj);     // 注意這裏!將拷貝構造函數聲明爲私有
public:
    Test()
    {
    }
};

template < typename T >
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}

typedef void(FuncT)(Test&, Test &);

int main()
{
    FuncT* pt = Swap;    // 編譯器自動推導 T 爲 Test

    return 0;
}
輸出:【g++】
test.cpp: In function ‘void Swap(T&, T&) [with T = Test]’:
test.cpp:27:   instantiated from here
test.cpp:8: error: ‘Test::Test(const Test&)’ is private
test.cpp:18: error: within this context

分析:
FuncT* pt = Swap; ==>
編譯器自動類型推導, T 爲Test類型 ==> 生成對應的 Swap 函數 ==> 語法檢查拷貝構造函數爲私有,給出錯誤提示

多參數函數模板

  • 函數模板能夠定義任意多個不一樣的類型參數
template < typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
    return static_cast<T1>(a + b);
}

==>編譯器

int r = Add<int, float, double>(0.5, 0.8);
  • 對於多參數函數模板it

    • 沒法自動推導返回值類型
    • 能夠從左向右部分指定參數類型
// T1 = int, T2 = double, T3 = double
int r1 = Add<int>(0.5, 0.8);
    
// T1 = double, T2 = double, T3 = float
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);

工程中將返回值參數做爲第一個類型參數io

編程實驗: 多參數函數模板

#include <iostream>

using namespace std;

template < typename T1, typename T2, typename T3 >
T1 Add(T2 a, T3 b)
{
    return static_cast<T1>(a + b);
}

int main()
{
    // T1 = int, T2 = double, T3 = double
    int r1 = Add<int>(0.5, 0.8);
    
    // T1 = double, T2 = double, T3 = float
    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);

    cout << "r1 = " << r1 << endl;
    cout << "r2 = " << r2 << endl;
    cout << "r3 = " << r3 << endl;

    return 0;
}
輸出:
r1 = 1
r2 = 1.3
r3 = 1.3

有趣的問題:
當函數重載碰見函數模板會發生什麼?編譯

重載函數模板

  • 函數模板能夠像普通函數同樣被重載

    • C++ 編譯器優先考慮普通函數
    • 若是函數模板能夠產生更好的匹配,那麼選擇模板
    • 能夠經過空模板實參列表限定編譯器只匹配模板
int r1 = Max(1, 2);
double r2 = Max<>(0.5, 0.8);

實例分析: 重載函數模板

#include <iostream>

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;
}
輸出:
int Max(int a, int b)
2
T Max(T a, T b)
2
T Max(T a, T b)
4
T Max(T a, T b, T c)
T Max(T a, T b)
T Max(T a, T b)
7
int Max(int a, int b)
100

小提示:
Max('a', 100) 普通函數被調用
函數模板自己不容許隱式類型轉換,普通函數被匹配後進行隱式類型轉換

小結

  • 函數模板經過具體類型產生不一樣的函數
  • 函數模板能夠定義任意多個不一樣的類型參數
  • 函數模板中的返回值類型必須顯示指定
  • 函數模板能夠像普通函數同樣被重載

以上內容參考狄泰軟件學院系列課程,請你們保護原創!

相關文章
相關標籤/搜索