C++テンプレートの特化問題について簡単に述べる.

4313 ワード

C++にはクラステンプレートと関数テンプレートの2種類のテンプレート方式があり,テンプレート特化も全特化と偏特化の2種類に分けられる.
まず次のテンプレートを見てみましょう
#include 

//    
template 
class Base{
private:
    T1 n1;
    T2 n2;
public:
    Base(T1 n1_t,T2 n2_t):n1(n1_t),n2(n2_t){}
    void show()const{
        std::cout << "#1:" << n1 << "," << n2 << std::endl;
    }
};

//     
template 
class Base{
private:
    char n1;
    T2 n2;
public:
    Base(char n1_t,T2 n2_t):n1(n1_t),n2(n2_t){}
    void show()const{
        std::cout << "#2:" << n1 << "," << n2 << std::endl;
    }
};

//     
template <>
class Base{
private:
    double n1;
    double n2;
public:
    Base(double n1_t,double n2_t):n1(n1_t),n2(n2_t){}
    void show()const{
        std::cout << "#3:" << n1 << "," << n2 << std::endl;
    }
};

int main(){
    using namespace std;

    Base s1('A',11);            //             
    Base s2(20,20);              //           
    Base s3(13.5,26.5);    //             
    s1.show();
    s2.show();
    s3.show();

    return 0;
}

一般的なテンプレートの定義形式に詳しいと思いますが、ここではテンプレートの特化時の定義形式についてお話しします.
テンプレートの特化とは何でしょうか.どんな役割がありますか.テンプレートの特化はテンプレートの具体化とも呼ばれ、テンプレートパラメータが特定のタイプで具体的に実現されることを指す.テンプレートのインスタンス化時にテンプレートの優先度を合わせるために使用されます.
テンプレートでの優先順位の一致:テンプレートのフル特化>テンプレートの偏特化>通常のテンプレート
テンプレート偏特化は、既存のテンプレートに対して部分的に具体化され、元のテンプレートパラメータリストのいくつかの汎用パラメータを特定のタイプに指定するために使用されます.上記コードでは、テンプレートパラメータリストのT 1を特定のタイプのcharとして指定する、2番目のテンプレートパラメータT 2は指定されていない、クラステンプレートをインスタンス化する必要がある場合、指定したテンプレートの1番目のパラメータタイプがcharである場合、通常のテンプレートよりもマッチング度が高いため、このオフセットバージョンを優先してインスタンス化するもちろん、これは、特定のフル特化バージョンがない場合、フル特化が一致し、偏特化や通常のテンプレートよりも優先度が高いためです.
上記のコードに示すように、s 1オブジェクトのインスタンス化にはcharとintタイプが1つ提供され、1つ目のタイプはBaseテンプレートのオフセットとちょうど一致するので、このオフセット化バージョンを優先してオブジェクトをインスタンス化するので、s 1.show()は#2の文を出力します.
s 2オブジェクトは2つのintタイプを提供し、これはテンプレートのフル特化バージョンと偏特化バージョンと一致しないため、通常のテンプレートを用いてインスタンス化する.show()ですので#1の文を出力します.
s 3オブジェクトは2つのdoubleタイプを提供し、これはテンプレートのフル特化と一致するので、このテンプレートのフル特化バージョンを用いてインスタンス化する、s 3.show()は#3の文を出力します.
上のコードの実行後の出力:
#2:A,11
#1:20,20
#3:13.5,26.5

関数テンプレートの定義形式はクラステンプレートと似ていますが、現在の関数テンプレートではオフセットは許可されず、フル特化のみが許可されていますが、関数テンプレートは関数テンプレートの再ロードによって「オフセット」を実現できます.コード:
//       
template  
void func(const T1& a , const T2& b){  
    std::cout << "#1:" << a << "," << b << std::endl;
}  

//         
template<>  
void func(const int& a, const char& b){  
    std::cout << "#2:" << a << "," << b << std::endl;
}  

/*
//  !             
template 
void func(const double& a,const T2& b){
    std::cout << "#3:" << a << "," << b << std::endl;
}
*/

//            “   ”
template 
void func(const double& a,const T2& b){
    std::cout << "#4:" << a << "," << b << std::endl;
}

int main(){
    using namespace std;

    func(13,20);   //$1
    func(66,'T');           //$2
    func(96.5,10);     //$3

    return 0;
}
関数テンプレートの定義形式はクラステンプレートと似ているが、関数テンプレートには偏特化は存在せず、全特化のみであるため、クラステンプレート方式で偏特化バージョンを宣言するとコンパイラは許されない.もちろん,関数テンプレートの重荷による変相による「偏特化」効果は可能であるが,関数テンプレートに偏特化があるわけではない.
上記のコード$1関数では、2つのintタイプを関数テンプレートのタイプパラメータとして使用します.一致する特化バージョンは存在しないため、コンパイラは通常の関数テンプレートを使用して関数を定義し、プログラムに呼び出され、$2が1文を呼び出して出力します.ここまで$2は他のテンプレート関数呼び出し形式とは異なり、テンプレートパラメータのタイプを指定していないことがわかりました.これも許可されています(関数テンプレートのみ)コンパイラは、テンプレート関数を呼び出すときに指定したパラメータタイプを表示しなくてもよいし、指定されていない場合、コンパイラは関数パラメータリストから解析タイプを行うので、$2の呼び出し形式はfunc(66,'T')に相当します.クラステンプレートでは許可されていません.したがって、$2のパラメータタイプは関数テンプレートのフル特化バージョンと一致し、コンパイラはテンプレートのフル特化バージョンを定義し、プログラムによって呼び出され、2文が出力され、$3は関数テンプレートのリロード形式との一致が通常のテンプレートよりも高いため、#4文が呼び出され、出力される.
上の関数のテンプレート部分のプログラム出力:
#1:13,20
#2:66,T
#4:96.5,10

以上、模版の特化問題についての浅談ですが、問題があれば、指摘して、共に進歩してください.