[C ++詳細分析] 42、関数テンプレートとその必須分析

関数本体が同じ関数の場合、関数テンプレートを使用して解決できるのは、パラメータータイプが異なる関数のみですこれは、C ++の汎用プログラミングです。

1関数テンプレート

関数テンプレートは、さまざまなタイプで呼び出すことができる特別な関数です。
ここに画像の説明を挿入

1.1関数テンプレートの構文規則

  • テンプレートキーワードは、一般的なプログラミングの開始を宣言するために使用されます
  • typenameキーワードは、一般的なプログラミングを宣言するために使用されます

ここに画像の説明を挿入

1.2関数テンプレートの使用

  • 自動型推論呼び出し
  • 特定のタイプの表示呼び出し

使用方法は次のとおりです。
ここに画像の説明を挿入

プログラミング実験:テンプレート関数の予備調査

// 42-1.cpp
#include<iostream>
#include<string>
using namespace std;
template<typename T>
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}
template<typename T>
void Sort(T a[], int len)
{
    for (int i = 0; i < len; i++)
    {
        for (int j = i; j < len; j++)
        {
            if (a[i] > a[j])
            {
                Swap(a[i], a[j]);
            }
        }
    }
}
template<typename T>
void print(T a[], int len)
{
    for (int i = 0; i < len; i++)
    {
        cout << a[i] << ", ";
    }
    cout << endl;
}
int main()
{
    int a[5] = {4, 5, 1, 3, 2};
    Sort(a, 5);
    print(a, 5);
    string s[5] = {"Java", "C++", "Go", "Python", "C"};
    Sort(s, 5);
    print(s, 5);
    return 0;
}
$ g++ 42-1.cpp -o 42-1
$ ./42-1
1, 2, 3, 4, 5, 
C, C++, Go, Java, Python, 

2関数テンプレートの本質

コンパイラーは関数テンプレートを2回コンパイルします

  • テンプレート自体をコンパイルする
  • パラメータ置換後にコードをコンパイルします

注:関数テンプレート自体は暗黙的な型変換を許可していません

  • タイプを自動的に導出する場合、厳密に一致させる必要があります
  • 表示タイプを指定すると、暗黙的なタイプ変換を行うことができます

プログラミング実験:関数テンプレートの本質

// 42-2.cpp
#include<iostream>
using namespace std;
class Test
{
    Test(const Test&);
public:
    Test()
    {
    }
};
template<typename T>
void Swap(T& a, T& b)
{
    T c = a;
    a = b;
    b = c;
}
// 使用typedef定义函数类型
typedef void(FuncI)(int&, int&);
typedef void(FuncD)(double&, double&);
typedef void(FuncT)(Test&, Test&);
int main()
{
    FuncI* pi = Swap;
    FuncD* pd = Swap;
    //FuncT* pt = Swap;
    cout << "pi = " << reinterpret_cast<void*>(pi) << endl;
    cout << "pd = " << reinterpret_cast<void*>(pd) << endl;
    //cout << "pt = " << reinterpret_cast<void*>(pt) << endl;
    return 0;
}
  • typedefを使用して3つの関数タイプを定義します。関数テンプレートコンパイラは1回コンパイルする必要があり、パラメータ置換後のコードも1回コンパイルする必要があります。25行目と26行目では、2つのポインタが2つの特定の関数を指しています。
  • クラスTestのコピーコンストラクターはプライベートとして定義されていますが、特定のコードを生成すると、プライベートコンストラクターは割り当てを完了できず、コンパイルエラーが発生します。コンパイラーがテンプレート自体をコンパイルする必要があること、および置き換えられたコードもコンパイルする必要があることが再度確認されます。

コンパイルして実行

$ g++ 42-2.cpp -o 42-2
$ ./42-2
pi = 0x55daa8490a01
pd = 0x55daa8490a2e

関数ポインタのアドレスが異なることがわかります。

3マルチパラメーター関数テンプレート

  • 関数テンプレートは、さまざまなタイプのパラメーターをいくつでも定義できます

ここに画像の説明を挿入
マルチパラメーター関数テンプレートの場合

  • 戻り値の型を自動的に導出することはできません
  • 型パラメーター左から右に指定できます

ここに画像の説明を挿入
プロジェクトの最初のタイプパラメータとして戻り値パラメータ

プログラミング実験:マルチパラメーター関数テンプレート

// 42-3.cpp
#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()
{
    int r1 = add<int>(0.5, 0.8);
    double r2 = add<double, float>(0.5, 0.8);
    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を解くとき、T1はint、T2はdouble、T3はdoubleです
  • r2を解くとき、T1はdouble、T2はfloat、T3はdoubleです。
  • r2を解くとき、T1は浮動小数点数、T2は浮動小数点数、T3は浮動小数点数
$ g++ 42-3.cpp -o 42-3
$ ./42-3
r1 = 1
r2 = 1.3
r3 = 1.3

4関数テンプレートは関数のオーバーロードに対応

関数テンプレートは通常の関数のようにオーバーロードできます

  • 通常の機能を優先する
  • 関数テンプレートがより適切な一致を生成できる場合は、テンプレートを選択します
  • 空のテンプレート引数リストを持つテンプレートのみに一致するようにコンパイラーを制限できます

ここに画像の説明を挿入

// 42-3.cpp
#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 << endl;			// 普通函数 MAX(int, int)
    cout << MAX<>(a, b) << endl << endl;		// 函数模板 MAX<int>(int, int)
    cout << MAX(3.0, 4.0) << endl << endl;		// 函数模板 MAX<double>(double, double)
    cout << MAX(5.0, 6.0, 7.0) << endl << endl;	// 函数模板 MAX<double>(double, double, double)
    cout << MAX('a', 70) << endl << endl;		//  普通函数 MAX(int, int)
    return 0;
}

優先度は通常の関数に与えられます。関数テンプレートがより一致する場合、テンプレートが選択されます。空のテンプレート引数リストを使用して、テンプレートのみに一致させることもできます

コンパイルして実行

$ g++ 42-4.cpp -o 42-4
$ ./42-4
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)
97

5まとめ

1.関数テンプレートは、実際のパラメーターに従ってパラメータータイプを
推定できます。2 . 自動的にタイプを推定して呼び出すことができます。また、指定されたパラメータータイプを表示することもできます。3.
関数テンプレートは、特定のタイプごとに異なる関数を生成します
。4.コールドテンプレートは、複数の異なるタイプパラメーターを定義できます
5.関数テンプレートはオーバーロード可能

298件のオリジナル記事を公開 181 件を賞賛 100,000回以上の閲覧

おすすめ

転載: blog.csdn.net/happyjacob/article/details/104505401