私の経験では、最新の C++ では、明示的な関数テンプレートの特殊化はめったに行われません。
まず、多くの点でテンプレート クラスの特殊化とはまったく異なる動作をするため、テンプレート クラスの特殊化 (はるかに一般的です) に慣れているプログラマーは、直感がひっくり返るでしょう。
第 2 に、関数のオーバーロード、テンプレート パターン マッチング、および明示的なテンプレートの特殊化はすべて、呼び出されるコードに影響を与え、3 つすべてが同じポイントで発生する傾向があるためです。関数のオーバーロードとテンプレート パターン マッチングは、最初から複雑です。明示的なテンプレートの特殊化により、さらに複雑なレイヤーが追加され、コードが理解しにくくなります。そのコストを正当化する必要があります。
第三に、言語が発明されて以来、より強力なテクニックを学んできたからです。ディスパッチにタグを付けたり、特性クラスにディスパッチしたり、SFINAE を使用してテンプレートのオーバーロードを選択したりできます。それらの間で、明示的な特殊化ができるほとんどすべてのことを行うことができ、多くの場合、それ以上のことができます。
コードで使用した例を示します。、またはGetField
のいずれかを取得できる、メソッドがあります。、およびを公開できますが、多くの場合、これら 3 で動作するコードは対称的です。にすることで、動物の選択に同じコードをテンプレート化することができます。Cow
Duck
Otter
GetCow
GetDuck
GetOtter
GetField<Cow>
GetField
次に、これらの 3 つのタイプのみに特化しました。他の型を要求するとリンカー エラーが発生し、好みの統一された構文が得られます。の実装はGetField
3 つのタイプで異なりますが、使用方法は統一されています。
もし今日それを書くとしたら、GetField
代わりに次のようにします。
// a template for passing types as tags:
template<class T> struct tag{using type=T;};
// Type-specific getters:
Cow& GetField( tag<Cow> ) { /* impl */ }
Duck& GetField( tag<Duck> ) { /* impl */ }
Otter& GetField( tag<Otter> ) { /* impl */ }
// Template getter for "any" type:
template<class T>
auto GetField()->
decltype( GetField( tag<T>{} ) )
{
return GetField( tag<T>{} );
}
より良いエラー メッセージ (リンカ エラーの代わりにオーバーロードなし) が得られ、私の実装はGetField
テンプレートの特殊化ではなく標準の関数になります。この場合、テンプレート関数は単なるインターフェイスのグロスです。
特性型、タグ ディスパッチ、およびオーバーロードの力の間で、テンプレート関数の明示的な特殊化が最良の解決策だったケースにここ数年出くわしたことはありません。過去にそれを使用した問題を再検討するときは、通常、再考して他のものを使用します。テクニック。