クラステンプレートは部分特殊化(partial specialization)できるが、関数テンプレートやメンバ関数テンプレートは部分特殊化できない。
テンプレート | 多重定義 | 部分特殊化 | 明示的特殊化 |
---|---|---|---|
クラステンプレート | × | ○ | ○ |
関数テンプレート | ○ | × | ○ |
部分特殊化よりも多重定義のほうがカバーできる範囲は少ない。
明示的特殊化と多重定義は被る(template<>プレフィクスをつけてもつけなくても動作が同じ)になる場合がある。
例)
#include <iostream> template<typename T> T func(T value) { return value; } //関数の多重定義(部分特殊化ではないことに注意。)そもそも、関数テンプレートは部分特殊化できない。 template<typename T> T func(T* value) { return (*value) * 2; } //こっちだと、関数の多重定義 //int func(int value) //{ // return 1; //} //こっちだと明示的特殊化 template<> int func(int value) { return value << 2; } int main(void) { std::cout << func(3) << std::endl; int n = 3; int* pn = &n; std::cout << func(pn) << std::endl; return 0; }
テンプレート引数が複数の場合は、「関数テンプレートやメンバ関数テンプレートは部分特殊化できない」ということに特に気を付ける必要がある。
一方を明示的に特殊化(下の場合はint sizeの部分)しても、残りのテンプレート(typename Tの部分)が特殊化されていない場合は、部分特殊化であることには変わりがない。結構はまったのでメモ。
template<typename T, int size> T make_rev(const T init) { return init*size; } //関数テンプレートの部分特殊化はできない //template<typename T> //T make_rev<T, 0>(const T init) //{ // return init; //}
こんなことをしたかったら、クラステンプレート(struct)の部分特殊化をすればよい:
#include <iostream> #include <vector> template<typename T, int size> struct Make_rev { static T func(const T init) { return init*size; } }; //クラステンプレートの部分特殊化は可能 template<typename T> struct Make_rev<T, 0> { static T func(const T init) { return init; } }; int main(void) { std::cout << Make_rev<int, 3>::func(5) << std::endl; std::cout << Make_rev<int, 0>::func(5) << std::endl; return 0; }
メンバ関数テンプレートも基本的な考え方は同じ:
#include <iostream> #include <vector> template<typename T, int size> struct Make_rev; template<typename T> class Test { private: T value; public: Test(T value) : value(value) {} ~Test() = default; template<int size> T rev(const T init) { //sizeのみの部分特殊化を行いたい。 return Make_rev<T, size>::func(init, value); } }; template<typename T, int size> struct Make_rev { static T func(const T init, const T value) { return init*size * value; } }; //クラステンプレートの部分特殊化は可能 template<typename T> struct Make_rev<T, 0> { static T func(const T init, const T value) { return init * value; } }; int main(void) { Test<int> t(7); std::cout << t.rev<3>(5) << std::endl; std::cout << t.rev<0>(5) << std::endl; return 0; }