2

私は C++ に関する本を読んでいますが、何らかの理由で、関数のテンプレートの特殊化 (暗黙的なテンプレートのインスタンス化、明示的なテンプレートのインスタンス化、および明示的な特殊化) を理解できないようです。

明確にするために、一般的なテンプレート関数と特殊化の両方をオーバーライドする非テンプレート関数を宣言/定義できる場合に、明示的なテンプレートのインスタンス化または明示的な特殊化の必要性を理解していません。

いつ、どこで、なぜ明示的なテンプレートのインスタンス化や関数の明示的な特殊化を使用しますか?

4

2 に答える 2

2

私の経験では、最新の C++ では、明示的な関数テンプレートの特殊化はめったに行われません。

まず、多くの点でテンプレート クラスの特殊化とはまったく異なる動作をするため、テンプレート クラスの特殊化 (はるかに一般的です) に慣れているプログラマーは、直感がひっくり返るでしょう。

第 2 に、関数のオーバーロード、テンプレート パターン マッチング、および明示的なテンプレートの特殊化はすべて、呼び出されるコードに影響を与え、3 つすべてが同じポイントで発生する傾向があるためです。関数のオーバーロードとテンプレート パターン マッチングは、最初から複雑です。明示的なテンプレートの特殊化により、さらに複雑なレイヤーが追加され、コードが理解しにくくなります。そのコストを正当化する必要があります。

第三に、言語が発明されて以来、より強力なテクニックを学んできたからです。ディスパッチにタグを付けたり、特性クラスにディスパッチしたり、SFINAE を使用してテンプレートのオーバーロードを選択したりできます。それらの間で、明示的な特殊化ができるほとんどすべてのことを行うことができ、多くの場合、それ以上のことができます。

コードで使用した例を示します。、またはGetFieldのいずれかを取得できる、メソッドがあります。、およびを公開できますが、多くの場合、これら 3 で動作するコードは対称的です。にすることで、動物の選択に同じコードをテンプレート化することができます。CowDuckOtterGetCowGetDuckGetOtterGetField<Cow>

GetField次に、これらの 3 つのタイプのみに特化しました。他の型を要求するとリンカー エラーが発生し、好みの統一された構文が得られます。の実装はGetField3 つのタイプで異なりますが、使用方法は統一されています。

もし今日それを書くとしたら、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テンプレートの特殊化ではなく標準の関数になります。この場合、テンプレート関数は単なるインターフェイスのグロスです。

特性型、タグ ディスパッチ、およびオーバーロードの力の間で、テンプレート関数の明示的な特殊化が最良の解決策だったケースにここ数年出くわしたことはありません。過去にそれを使用した問題を再検討するときは、通常、再考して他のものを使用します。テクニック。

于 2015-07-22T13:53:20.537 に答える