xrea-banner xreaad

部分特殊化

namespace kilrey; / C 言語, C++ / Template / 部分特殊化

前のページ(型変換)へ / 次のページ(不定長 template 引数)へ

template 関数の部分特殊化についてです。 部分特殊化というのは

template <typename T>
void test() {
    cout << "test(T)" << endl;
}

template <typename T>
void test<T*>() {
    cout << "test(T*)" << endl;
}
    

のように特殊化した後の関数も template 関数である場合です。 そうは言っても template 関数の部分特殊化は C++ の言語仕様で禁止されているので実際には使うことが出来ません。 幸いなことにこの制限を比較的容易に回避する方法が知られています。

#include <iostream>
using namespace std;

template <typename T> class Holder;

template <typename T> class Holder {
    template <typename U>
    friend void test();
    static void _test() {
        cout << "test(T)" << endl;
    }
};
template <typename T> class Holder<T*> {
    template <typename U>
    friend void test();
    static void _test() {
        cout << "test(T*)" << endl;
    }
};

template <typename T>
inline void test() {
    Holder<T>::_test();
}

int main() {
    test<int>();
    test<int*>();
    return 0;
}
    

というように部分特殊化したクラスの静的メンバ関数として実装し、 呼び出し関数を通して実行するのです。 そうすると呼び出し側のインターフェースとしては 関数の部分特殊化したものとほぼ同じものになります。 ちなみに test() を inline 化することで呼び出しコストを減らしたり、 各実装の _test() を private にした上で test() を friend 指定して外部からは呼べないようにしたり、 といった細かい工夫もしてあります。

template 関数の部分特殊化が出来ない明確な理由は判りません。 クラスは部分特殊化出来るのですから関数も出来そうな気もしますが、 オーバーロードとの兼ね合いが問題なのでしょうか。 ただ、標準委員会では出来るようにしようという議論もあるようなので 将来は template 関数も部分特殊化出来るようになるかもしれません。

前のページ(型変換)へ / 次のページ(不定長 template 引数)へ