メンバ関数テンプレートの部分特殊化 vs オーバーロード
メンバ関数テンプレートの挙動を、とある引数に対してのみ変更したい場合の選択肢としてテンプレートの特殊化とオーバーロードがあります。
struct ClassA {
// メンバ関数テンプレート
template<typename T> void Func(T value) {
...
}
// テンプレートの特殊化
template<> void Func<int>(int value) {
...
}
// オーバーロード
void Func(float value) {
...
}
};
優柔不断な自分はここで、テンプレートの特殊化にするかオーバーロードにするか悩みました。
で、それぞれのメリット・デメリットを考えてみました。
テンプレートの特殊化
メリット
・ClassAを定義しているヘッダファイルを変更することなく、新しい特殊化を追加できる。
例えば、
ファイル ClassA.h
struct ClassA {
// テンプレートメンバ関数
template<typename T> void Func(T value) {
...
}
};
ファイル ClassAUserImpl.cpp
#include "ClassA.h"
// テンプレートの特殊化
template<> void ClassA::Func<int>(int value) {
...
}
ということが可能で、特殊化に関しては「クラスの使用者側で必要になり次第勝手に(自己責任で!)特殊化してください」ということができます。
これはメリットであると共にデメリットにもなりうるかもしれません。
デメリット
・古いコンパイラだとテンプレートの部分特殊化を使用できない。
オーバーロード
メリット
・テンプレートではないのでメンバ関数の実装をインラインに書く必要がない。
・C++の基本なので読みやすい(?)
デメリット
・特になし
ちなみに、テンプレートの特殊化とオーバーロードを同じ型に対して同時に行うとどうなるのかと思って試してみたところ、オーバーロードが優先されました。(VC7.1)
3 コメント:
実装ではオーバーロードが優先されたみたいだけど,
仕様では明記されてないんかな?
どっちかといえば特殊化のほうがぴったりくるよな.
俺ならそうすると思う.
メリットやデメリットでどう実装するかを決めるのも大切だけど,
一貫性も大切だと思います.
なるほど、一貫性かー。そういう視点は思いつかなかった。
結局今回はテンプレートの部分特殊化を選択したけど、他の人にメンテナンスを頼むとなったときに、その人がテンプレートをきっちり理解している必要があるという難点も…。
テンプレートの部分特殊化とオーバーロードの優先権についてはまた仕様さがしておきます。
調べてみたところ、型が一致した場合はオーバーロードが優先されるらしい。
(プログラミング言語C++ 第3版 13.3.2)
コメントを投稿