37章 テンプレートの特殊化

http://www.geocities.jp/ky_webid/cpp/language/037.html

基本的にはテンプレート使いたいけど、ある型のときだけ別の処理にしたいというときに使えるのがテンプレートの特殊化という機能です。

#include <iostream>
using namespace std;

template<class T>
class CSample {
public:
    CSample(T t) : m_t(t) {}
    T Get() { return m_t; }
private:
    T m_t;
};

template<>
class CSample<int> {
public:
    CSample(int t) : m_t(t) {}
    int Get() { return m_t + 100; }
private:
    int m_t;
};

int main () {
    CSample<long> obj1(100);
    CSample<int>  obj2(100);
    
    cout << obj1.Get() << endl;
    cout << obj2.Get() << endl; // intの時だけ100足される
    
    return 0;
}
$ main
100
200

うまくいってますね。

しかしこれ、場合によってはかなりのコードの二重化が発生しそうです。

しかもテンプレートなので共通化もできそうにないですし。

ふと思ったんですが、上記のような処理であれば、オーバーライドでできないもんでしょうか?

やはりテンプレートの定義と、普通の型の定義は両立できない?

一応試してみました。

#include <iostream>
using namespace std;

template<class T>
class CSample {
public:
    CSample(T t) : m_t(t) {}
    T Get() { return m_t; }
    int Get() { return m_t + 100; } // intの時だけ別処理
private:
    T m_t;
};

int main () {
    CSample<long> obj1(100);
    CSample<int>  obj2(100);
    
    cout << obj1.Get() << endl;
    cout << obj2.Get() << endl;
    
    return 0;
}

コンパイルエラーがどっさりorz

やはり無理なんですね。

次に、テンプレートの特殊化は当然関数にも適応できます。

#include <iostream>
using namespace std;

template<class T> void foo (T t) { cout << t << endl; }
template<> void foo<int>(int t)  { cout << t+100 << endl; }

int main () {
    
    foo("abc");
    foo(100);
    
    return 0;
}
$ main
abc
200

このようにintの時だけ100足されてますね。

さて、上記では

template<> void foo<int>(int t)

と書きましたが、実はもう少し省略できます。

template<> void foo(int t)

テンプレートの特殊化であることはわかっているのでfooの後ろのは引数から判断できるので省略できるということです。