Step By Step(C++テンプレートのリロードと特化)

17035 ワード

一、テンプレート関数のリロード:関数のリロードは非常に汎用的で理解しやすいプログラミング基礎概念であり、関数名が同じで関数署名が異なる関数のセットであり、実際の呼び出しでは、コンパイラは関数パラメータの違いに応じて最も適切で最も特化した関数を自動的に選択する.推論の過程で、複数の関数が呼び出しルールに合致する場合、コンパイラは内蔵された特化ルールに基づいて、最も特殊な関数を候補関数として選択します.しかし、複数の候補関数が残っている場合、コンパイラは二義的なエラーを報告します.通常の関数と同様に、C++でもテンプレート関数は関数のリロード機能をサポートし、テンプレート関数を通常の関数と混合して、より柔軟な関数のリロードの効果を達成することができます.ここでは,関数リロードの概念自体についてあまり説明するのではなく,テンプレート関数リロードの応用シーンと応用テクニックに重点を置く.次に、テンプレート関数を使用してハッシュ値を再ロードして計算するコードの例を示します.
 1     #include <stdio.h>

 2     

 3     template<typename T> 

 4     int hash_code(T v) {

 5         return v.hashCode() * 2;

 6     }

 7     

 8     template<typename T>

 9     int hash_code(T* v) {

10         return v->hashCode();

11     }

12     

13     int hash_code(const int v) {

14         return v + 100;

15     }

16     

17     class HashClass {

18     public:

19         HashClass(int v) : _v(v) {}

20         int hashCode() {

21             return _v + 200;

22         }

23     

24     private:

25         int _v;

26     };

27     

28     int main() {

29         HashClass c1(10);  //    template<typename T> int hash_code(T v)

30         printf("The hash value is %d
",hash_code(c1)); 31 HashClass c2(20); // template<typename T> int hash_code(T* v) 32 printf("The hash value is %d
",hash_code(&c2)); 33 int i3 = 30; // int hash_code(const int v) 34 printf("The hash value is %d
",hash_code(i3)); 35 return 0; 36 } 37 38 //The hash value is 420 39 //The hash value is 220 40 //The hash value is 130

上記のサンプルコードではhash_code関数は、コンパイラにパラメータに応じて最適な候補関数を選択させることができる.ここでテンプレート関数は、通常の関数とともに関数の再ロードに関与します.テンプレート関数のリロードについては、主にアルゴリズムの分野に適用され、多くのタイプについては汎用アルゴリズムによって予想される効果を達成することができるが、特殊なタイプについては、関数のリロードによって、このタイプに対してより効率的なアルゴリズムを実現することができる.二、テンプレートクラス特化:テンプレートクラスにおいても、同様にテンプレート関数と同様の適用シーンが存在するが、テンプレートクラスにはテンプレートクラス特化された方法で存在する.次の例のコードは、生産者-消費者のタスクバッファキューです.キュー内の既存の要素を空にする場合は、要素オブジェクト自体が占有する可能性のあるシステムリソースを解放する方法も考慮する必要があります.ここでは、異なる要素タイプに基づいて、異なる要素解放クラスが与えられます.
 1     #include <stdio.h>

 2     #include <vector>

 3     

 4     using namespace std;

 5     

 6     class Runnable {  

 7     public:

 8         virtual void release() {

 9             delete this;

10         }

11     };

12     

13     class Closable {

14     public:

15         virtual void close() {

16             _db.close();

17             delete this;

18         }

19     private:

20         db_env _db;

21     };

22     

23     template<typename T>

24     class List {   //1

25     public:

26         void clear() { 

27             _taskList.clear();

28         }

29     private:

30         vector<T> _taskList;

31     };

32     

33     template<typename T>

34     class List<T*> {  //2

35     public:

36         void clear() {

37             for (int i = 0; i < _taskList.size(); ++i)

38                 delete _taskList[i];

39             _taskList.clear();

40         }

41     private:

42         vector<T*> _taskList;

43     };

44     

45     template<>

46     class List<char*> {  //3

47     public:

48         void clear() {

49             for (int i = 0; i < _taskList.size(); ++i)

50                 delete [] _taskList[i];

51             _taskList.clear();

52         }

53     private:

54         vector<char*> _taskList;

55     };

56     

57     template<>

58     class List<Runnable*> {  //4

59     public:

60         void clear() {

61             for (int i = 0; i < _taskList.size(); ++i)

62                 _taskList[i]->release();

63             _taskList.clear();

64         }

65     private:

66         vector<Runnable*> _taskList;

67     };

68     

69     template<>

70     class List<Closable*> {  //5

71     public:

72         void clear() {

73             for (int i = 0; i < _taskList.size(); ++i)

74                 _taskList[i]->close();

75             _taskList.clear();

76         }

77     private:

78         vector<Runnable*> _taskList;

79     };

80     

81     int main() {

82         List<Runnable*> listRunnable;  //  No 4

83         List<Closable*> listClosable;  //  No 5

84         List<int> listInt;             //  No 1

85         List<int*> listIntPointer      //  No 2

86         List<char*> listCharPointer;   //  No 3

87         return 0;

88     }

上記のコード例では、コンパイラはテンプレートパラメータに応じて異なるテンプレートクラスを選択しますが、これらは呼び出し元にとって完全に透明であり、今後新しい特殊なタイプを追加する場合は、そのタイプに新しい特化クラスを実装するだけでよいです.なお、このコードクリップは、このC++テンプレートの特徴を示すために完全に記述されており、参考に供する.