C ++テンプレートの概要に加えて、型以外のテンプレートパラメータ、テンプレートの特殊化の完全な特殊化、テンプレートを個別にコンパイルできない理由の実際の理解など、テンプレートのいくつかの特別な使用法(構文)

コンテンツ

1.テンプレートの非型パラメーター

2.テンプレートクラスとテンプレート関数の特殊化(完全な特殊化+部分的な特殊化)

3.テンプレートが個別のコンパイルをサポートしない理由の詳細な分析

4.テンプレートSTLのジェネリックプログラミング--STLライブラリの概要

V.記事の要約


1.テンプレートの非型パラメーター

  • 長い間使用されてきたテンプレート、通常はすべてのテンプレートに型パラメーターがありますが、予期せぬことに、テンプレートには型以外のパラメーターもあります。つまり、テンプレートのパラメーターは必ずしも型ではなく、整数にすることもできます。渡すことができるのは1つだけです。整数データ。整数定数...。
  • まず、次のコードについて考えてみましょう(質問を投げます
#define N 100
template <class T>
class Array {
public:
	int getSize() {
		return N;
	}
private:
	T a[N];
};

int main() {
	//上述这样我们我们可以封装得到一个 可以管理 静态的 a[N]的数组的一个Array类....
	//但是这样我们要是需要其他容量的一个静态数组的类,不就每一次需要不停的重新定义N?????
	//这样使用起来会非常麻烦  
	Array<int> a1;
	a1.getSize();
    return 0;
}
  • 上記の問題を解決する方法???STLライブラリの配列ソースコードが問題をどのように解決するかをご覧ください。   

非型テンプレートパラメータsize_tN..は、上記の配列クラスで使用されます。次に、次のコードで利点を説明できます。   

template <class T, size_t N>
class Array {
public:
	int getSize() {
		return N;
	}
private:
	T a[N];
};

int main() {
	Array<int, 10> a1;
	cout << a1.getSize() << endl;
	Array<int, 100> a2;
	cout << a2.getSize() << endl;
    return 0;
}

この時点で、上記のNは実際には整数定数に相当するため、静的配列の長さを指定するのに便利なグローバルマクロを定義する必要はありません。

2.テンプレートクラスとテンプレート関数の特殊化(完全な特殊化+部分的な特殊化)

  • テンプレートの特殊化の公式説明:一般化設計で特殊化バージョンを提供する(つまり、一般化バージョンの一部またはすべてのパラメーターに明示的な指定を与える)ために、すべての明示的な指定は完全な特殊化であり、一部の明示的な指定は部分的な特殊化です。 ..。。
  • 私の理解:テンプレートの特殊化は、コンパイラーに直接かつ通常、特別なシナリオでテンプレートをインスタンス化させることであり、達成したい効果を得ることができません。この時点で、このシナリオに特別なシナリオを提供します。ルート特殊化インスタンスバージョン。この場合を処理するには...
  • 特殊なシナリオの特殊なバージョンは、次のようにシミュレートされます。たとえば、テンプレート関数で、文字列が同じかどうかを比較する場合は、コードを直接記述し、次のように結果をテストします(特殊なバージョンは提供されていません)。
    template<class T>
    bool IsEqual(const T& a, const T& b) {
    	return a == b;
    }
    int main() {
    	cout << IsEqual(1, 1) << endl;
    	cout << IsEqual(1.1, 1.1) << endl;
    	char s1[] = "1234";
    	char s2[] = "1234";
    	cout << IsEqual(s1, s2) << endl;
    	char *s3 = "1234";
    	char *s4 = "1234";
    	cout << IsEqual(s3, s4) << endl;
    	while (1);
    	return 0;
    }

    上記のコードの結果は、リーダーでテストする必要があります。結果も非常に単純であり、要件を満たすことができません。文字列のテンプレートを比較および等化する機能を実現できません。どうすればよいですか?特別なバージョンのインスタンスを提供します。私たちが望む結果をサポートするために。

専用バージョンを提供した結果は以下のとおりです。  

template<class T>
bool IsEqual(const T& a, const T& b) {
	return a == b;
}
//针对字符串类型进行特殊处理 -- 写一份特例出来
bool IsEqual(const char* s1, const char* s2) {
	return strcmp(s1, s2) == 0;
}
int main() {
	cout << IsEqual(1, 1) << endl;
	cout << IsEqual(1.1, 1.1) << endl;
	char s1[] = "1234";
	char s2[] = "1234";
	cout << IsEqual(s1, s2) << endl;
	char *s3 = "1234";
	char *s4 = "1234";
	cout << IsEqual(s3, s4) << endl;
	while (1);
	return 0;
}

上記は関数テンプレートの特殊化であり、その後にクラステンプレートの特殊化が続きます。最初は構文形式です。次のコードスニペットのようになります。

template <>               //<>不一定是空, 空代表全特化, 否则偏特化					
class testClass <type, type, ...> { // <type, type, ...> 就是具体的特化类型....

};

次に、完全に専門化された実際のケースがあります:(ケースの結果を貼り付けずに、読者が自分で確認し、どのクラスが入力されたかをデバッグできることを願っています)

//测试类模板
template <class T1, class T2> 
class TestClass {
public:
	TestClass() {
		cout << "T1, T2" << endl;
	}
};
//模板特化案例
template<>
class TestClass<int, int> {					//特化一个int,int 版本调用这个
public:
	TestClass() {
		cout << "int, int" << endl;
	}
};
//hash类模板
template <class Key>						 
struct hash{};
//模板的特化案例
template<>
struct hash<char> {
	size_t operator ()(char x) const { return x; }
};

template<>
struct hash<int> {
	size_t operator ()(int x) const { return x; }
};

template<>
struct hash<long> {
	size_t operator ()(long x) const { return x; }
};

int main() {
	cout << hash<int>()(1000) << endl;
	cout << hash<int>()('a') << endl;//可通过 f9断点 + f10 f11测试进入类
	TestClass<int, int> obj1;
	TestClass<int, double> obj2;
}
  • テンプレートの部分的特殊化、部分的特殊化-最初のタイプ(部分の数)
  • 以下はまだ量的なバイアスです、読者は自分でテストすることができます
  • template <class T1, class T2> 
    class TestClass {
    public:
    	TestClass() {
    		cout << "T1, T2" << endl;
    	}
    };
    
    template<class T1>
    class TestClass<T1, int> {//只要T2是int走这个
    public:
    	TestClass() {
    		cout << "T1, int" << endl;
    	}
    };
    
    template<class T1>
    class TestClass<T1, char> {//只要T2是char走这个
    public:
    	TestClass() {
    		cout << "T1, char" << endl;
    	}
    };
    //上述是仅仅针对T2做的特化处理
    int main() {
    	TestClass<char, char> t1;
    	TestClass<char, int> t2;
    	TestClass<char, double> t3;
    	return 0;
    }
  •  部分的なスペシエーション、テンプレートの部分的なスペシャライゼーション-範囲の部分的なスペシャライゼーション(読者が自分でテストして分析できることを願っています)
    //测试类模板
    template <class T1, class T2> 
    class TestClass {
    public:
    	TestClass() {
    		cout << "T1, T2" << endl;
    	}
    };
    
    //如下是范围上的偏特化, 数量上是全部, 但是范围进针对指针或者引用类型
    template<class T1, class T2>
    class TestClass<T1*, T2*> {
    public:
    	TestClass() {
    		cout << "T1*, T2*" << endl;
    	}
    };
    
    template<class T1, class T2>
    class TestClass<T1&, T2&> {
    public:
    	TestClass() {
    		cout << "T1&, T2&" << endl;
    	}
    };
    
    int main() {
    	TestClass<int*, char*> t4;
    	TestClass<int&, char&> t5;
    	return 0;
    }

3.テンプレートが個別のコンパイルをサポートしない理由の詳細な分析

  • テンプレートが個別のコンパイルをサポートしていない理由を分析するために、個別のコンパイルを試みて、どのエラーが報告されているかを確認します。
  • Vector.hコードの最初の部分:
    #pragma once
    #include <iostream>
    using namespace std;
    //只是放置申明....
    //放置类申明
    template <class T> 
    class Vector {
    public:
    	Vector();
    };
    //放置函数申明
    template <class T>
    T add(const T& left, const T& right);
  • 2番目の段落はVector.cppのコードです
    #include "Vector.h"
    
    //实现....
    template <class T>
    Vector<T>::Vector() {
    	cout << "构造" << endl;
    }
    
    //放置函数申明
    template <class T>
    T add(const T& left, const T& right) {
    	return left + right;
    }
  • 3番目の段落はtest.cppのコードです
    #include "Vector.h"
    int main() {
    	return 0;
    }

    オブジェクトを作成せずにコンパイルしたり、関数を呼び出したりしてもエラーは発生しないことがわかりました。終了し、文法上のエラーがないことを示しています。…

 上記のように、個別にコンパイルする場合、コンパイルフェーズ中にエラーメッセージは表示されません。

  • 次に、オブジェクトを作成するか、テンプレート関数を呼び出してインスタンス化し、効果を確認しますか?
  •  推測だけをテストしてください...   どちらも同じエラー現象、解析できない外部命令、それが何を意味するのか、そしてコンパイルエラーの分離の理由は、関数定義の実装がなく、関数宣言だけがあるかどうかです。。   

  • 関数宣言だけに関数の実装がないのはなぜですか 。この種のエラーは、リンクしている場合、特に個別にコンパイルしている   場合にのみ発生します。
  • 個別コンパイルのプロセスは次のように描かれています。

 上記は単なる推測ですが、正しいはずです。Vector.cppでテンプレートのインスタンス化が欠落しているかどうかを確認するには、ソリューション1です。推測を確認することもできます。手動で明示的なインスタンスを追加します。 Vector.cppのテンプレートが変更されました。

 上記の方法は、テンプレート関数の個別のコンパイルを解決できますが、非常に面倒で、クラス表示のインスタンス化に対処する方法がわかりません。知っている人は誰でもコメント領域に通知するのに役立ちます。 

  • テンプレートクラスとテンプレート関数の最も適切な処理。個別のコンパイルを実行せず、.hppファイルで定義を宣言して完了します。

4.テンプレートSTLのジェネリックプログラミング--STLライブラリの概要

アドバンテージ :

  • コードを再利用することは、原則として、汚い仕事はすべてコンパイラに任されています
  • テンプレートを使用すると、コードの一部を柔軟にすることができます

欠点:

  • テンプレートはコードを保存しているように見えますが、実際のコンパイル後にコードが膨張するという問題があります
  • vector <int> v1; vector <double> v2、vector <string> v3 ....もちろん、コードの膨張を可能な限り減らすために、コンパイラーは必要に応じてインスタンス化し、メンバー関数を呼び出します。
  • テンプレートで構文エラーが発生した後、エラーが混乱して不正確になることがあり、エラーの場所を特定するのは簡単ではありません。通常、最初のエラーのみが表示され、次のエラーのほとんどは不正確です。
  • テンプレートは個別のコンパイルをサポートしていません

V.記事の要約     

まず、この記事の4つのポイント: 

1.非型テンプレートパラメータ:ライブラリ内の配列template <class T、size_tN>テンプレートパラメータは整数定数にすることができます  

2.テンプレートの特殊化:特殊化の理由(特殊なシナリオでは、従来のテンプレートのインスタンス化では目的の結果が得られません。今回は特殊化インスタンスを指定します)、特殊化の種類(完全な特殊化、部分的な特殊化:数量オン、範囲オン

3.テンプレートが個別のコンパイルをサポートしない理由の本質から:個別のコンパイルプロセスから開始して、2つの.oファイルは、リンクされている場合にのみ相互作用します。前のコンパイル段階では、相互作用はなく、Vectorのテンプレートです。 cppをインスタンス化できませんでした...

4.テンプレートの長所と短所の要約長所、利便性コードの再利用、コンパイラのヘルプの例、短所:コードの拡張から始める

上記の簡単な要約として、それを思い出すことができれば、または上記の質問に頭の中ではっきりと答えることができれば、大丈夫です。混乱している場合は、振り返ることができます。気が散っているだけかもしれません。

最後に、この記事には、Hou Jie氏のコースウェアからのいくつかのレッスンと、すべての人と共通の進歩を共有することを学ぶための個人的なメモとしてのみ使用される私自身のメモと洞察が含まれています...不十分です、コメント欄にメッセージを残してください、私は共通の学習と進歩を望みます

おすすめ

転載: blog.csdn.net/weixin_53695360/article/details/122783549