いくつかの欠点は次のとおりです。
- その構文は複雑です
- コンパイラは余分なコードを生成します
それらを検証するのは難しいです。使用されないテンプレートコードは、ほとんどコンパイルされない傾向があります。したがって、テストケースを適切にカバーする必要があります。ただし、テストには時間がかかるため、そもそもコードが堅牢である必要がないことが判明する可能性があります。
うーん、どうでしょう…
3: コンパイルが遅くなる可能性がある
4: 実行時ではなくコンパイル時に計算するように強制します (実行時の柔軟性よりも高速な実行速度を好む場合、これも利点になります)。
5: 古い C++ コンパイラはそれらを処理しないか、正しく処理しません
6: コードを正しく理解していない場合に生成されるエラー メッセージは、ほとんど理解できない場合があります。
テンプレートは実装をコードのクライアントに公開するため、ライブラリの境界でテンプレート化されたオブジェクトを渡すと、ABI の維持が難しくなります。
これまでのところ、私がテンプレートで見つけた主な欠点について誰も言及していないようです。
私は構文の問題について言及しているわけではありません - はい、構文は醜いですが、私はそれを許すことができます。私が言いたいのは、これまでに見たことのないテンプレート化されていないコードで、アプリケーションがどんなに大きくても、最初から始めると、main()
通常、プログラムが何をしているかの大まかなストロークを問題なくデコードできることがわかりました。また、コードを単に使用しvector<int>
たり、同様のものを使用したりすることは、少しも気になりません。しかし、コードが単純なコンテナ タイプ以外の目的で独自のテンプレートを定義して使用し始めると、すぐに理解できなくなります。 そして、それはコードのメンテナンスに非常に悪い影響を及ぼします。
その一部は避けられません: テンプレートは、複雑な半順序オーバーロードの解決規則 (関数テンプレートの場合) と、程度は低いですが部分的な特殊化 (クラス テンプレートの場合) によって、より優れた表現力を提供します。しかし、ルールは非常に複雑であるため、コンパイラの作成者 (私よりも桁違いに頭が良いことを喜んで認めます) でさえ、まれなケースではまだ間違っています。
C++ での名前空間、フレンド、継承、オーバーロード、自動変換、および引数依存のルックアップの相互作用は、すでに十分に複雑です。しかし、テンプレートをミックスに追加し、それに伴う名前検索と自動変換のルールをわずかに変更すると、その複雑さは、人間が対処できない割合に達する可能性があります. 私は、これらすべての構造を利用するコードを読んで理解できるとは思っていません。
テンプレートとは無関係の問題として、STL コンテナーの内容を (たとえば C スタイルの配列と比較して) デバッガーが自然に表示することが依然として難しいということがあります。
唯一の本当の欠点は、テンプレート (特に他のテンプレートで使用されているもの) で小さな構文エラーを作成した場合、エラー メッセージが役に立たないことです... ほとんど使用できないエラー メッセージが 2 ページほど表示されることを期待してください;-)。コンパイラの欠陥はコンパイラ固有のものであり、構文は醜いものですが、実際には「複雑」ではありません。全体として、適切なエラー診断に関する大きな問題があるにもかかわらず、テンプレートは依然としてC++ の最高の機能の1 つであり、Java などのジェネリックの実装が劣っている他の言語よりも C++ を使用したくなる可能性があります。 ...
コンパイラが解析するのは複雑です。つまり、コンパイル時間が長くなります。また、高度なテンプレート構造を使用している場合、コンパイラ エラー メッセージを解析するのが難しい場合があります。
特にメタプログラミングのレベルでそれらを理解する人が少ないため、それらを維持できる人が少なくなります。
テンプレートを使用すると、コンパイラは実際に使用するものだけを生成します。Boost や Loki ライブラリのように非常に複雑な構造を使用する場合、コンパイル時間がかなり長くなる可能性があることを除けば、C++ テンプレート メタプログラミングを使用することに不利な点はないと思います。
欠点: テンプレート エラーは、テンプレートがインスタンス化されたときにのみコンパイラによって検出されます。テンプレートのメソッドのエラーは、テンプレートの残りの部分がインスタンス化されているかどうかに関係なく、メンバー メソッドがインスタンス化されている場合にのみ検出されることがあります。
テンプレート クラスのメソッドにエラーがあり、1 つの関数のみが参照されているが、他のコードがそのメソッドなしでテンプレートを使用している場合、コンパイラはエラーのあるメソッドがインスタンス化されるまでエラーを生成しません。
最悪の場合: 不適切なテンプレート コードから得られるコンパイラ エラー メッセージ。
私は何年にもわたって時々テンプレートを使用してきました。それらは便利かもしれませんが、専門的な観点からは、私はそれらから離れています. その理由は次の 2 つです。
a.) 関数定義 (宣言だけでなく) の「ソース」コードを「使用場所」コードに公開するか、b.) ソース ファイルにダミーのインスタンス化を作成する必要があります。これはコンパイルに必要です。オプション a.) は、ヘッダーで関数を定義するか、実際に cpp を含めることで実行できます。
C++ で (たとえば C# と比較して) ヘッダーを許容する理由の 1 つは、「インターフェイス」が「実装」から分離されているためです。テンプレートは、この哲学と矛盾しているようです。
テンプレート型パラメーターのインスタンス化によって呼び出される関数は、コンパイル時に適用されず、リンク エラーが発生する場合があります。例えば T の例。example.Compiler DoestKnowIfThisFunctionExistsOnT(); これは「緩い」私見です。
テンプレートではなく、派生/コンテナー クラスがコンパイル時に何が利用できるかを知る基本クラスを使用する傾向があります。基本クラスは、テンプレートがよく使用される汎用メソッドと「型」を提供できます。これが、必要に応じて継承階層にジェネリック基本クラスを挿入するために既存のコードを変更する必要がある場合に、ソース コードの可用性が役立つ理由です。それ以外の場合、コードがクローズド ソースの場合は、回避策としてテンプレートを使用する代わりに、汎用基本クラスを使用してコードを適切に書き直してください。
vector< T > のように型が重要でない場合は、単に「オブジェクト」を使用するのはどうですか。C++ は「オブジェクト」キーワードを提供していません。私は、特にコンパイラーやコードを読む人々に型が重要ではないことを伝えるのに役立つだろうと、Bjarne Stroustrup 博士に提案しました (そうでない場合)。C++11にはこれがあるとは思いませんが、おそらくC++14にはありますか?