テンプレートで解決できる問題を特定する方法に関するリソースはありますか?


8

テンプレートのメタプログラミングに関する知識を向上させることにしました。私は構文とルールを知っており、オンラインリソースの数え切れないほどの例で遊んでいます。

テンプレートがどれほど強力であり、コンパイル時間の最適化がどれだけ提供できるかを理解していますが、それでも「テンプレートを考える」ことはできません。特定の問題がテンプレートで最善に解決できるかどうか、そしてそれができるかどうか、私は自分で知ることができないようです。その問題をテンプレートに適応させる方法。

テンプレートを使用して最も適切に解決できる問題を特定する方法と、その問題をどのように適応させるかを教える、ある種のオンラインリソースまたは本はありますか?


5
あなたが持っているものがすべてハンマーである場合、すべてが釘のように見えます;-)すべてのすべてにテンプレートを使用することを考えすぎないでください。少なくとも、C ++標準の次のバージョンを設計するつもりがない場合は、そうしないでください。図書館。
ドクターブラウン

あなたは正しい、私は量産コードを見て、どこにでもTMPを適合させるつもりはありません:pこれは個人的な学習のためだけです、私はそれらがどれほど強力であるかを知っており、いくつかの優れたC ++プログラマー(動作するSTLなど)が大好きですMSの場合)は、特定の問題にTMPを非常に高速に適用でき、IRは非常に見栄えがします。STLには、channel9にいくつかのビデオがあり、TMPについて本当に感動しました。
SAP

回答:


8

書籍:

最新のC ++デザイン

C ++テンプレートメタプログラミング

再帰と関数型プログラミングに精通していることは、多くのtmpに関係することなので、大きなプラスになります。それは完全に進行中であり、本質的に何でも可能ですが、通常は、純粋な関数を定数に適用するか、他の型から型を生成することになります。

警告:tmpは、いいコードをスパゲッティに変える醜いモンスターです。使用すればするほど、C ++が気に入らなくなります。それは悪いことです。


1
「tmpは醜いモンスター」の+1。C ++は、他の言語と同様に、いくつかの点で優れています。しかし、メタプログラミングはその1つではありません。
ジョンパーディ

「モダンC ++デザイン」は古典的ですが、IIRCは、テンプレートとして実装する必要があるものを決定することよりも、巧妙なテンプレートトリックを使用して実装することを重視しています。いいえ。そのための1つの原則はおそらく「しないでください」-テンプレートが必要になる最も一般的な理由は、標準ライブラリ(特にC ++ 11)、Boost、およびその他の既存のライブラリですでにカバーされているため、自分のものは本当に日常のものではありません。
Steve314

C ++テンプレートメタプログラミングは、boostの一部のユーザーマニュアルにすぎません。適切なアプリケーションの選択や、C ++で同様のことを行う方法についてはあまり説明しません。
AProgrammer

6

Haskellやその他の純粋な関数型言語(Lisp、Scheme、OCamlなど)を学んでください。詳しくはWikipediaをご覧ください。

Haskellを検討すると、メタプログラミング機能の詳細については、こちらをご覧ください

テンプレートプログラミングは、実際にはほとんど同じルールに従います。


1
HaskellにはテンプレートHaskellという独自のテンプレートシステムがあることに注意してください。

2
@MattFenwick:うん。C ++テンプレートとは異なり、それはまだHaskellです。:)
Macke

私は大学での計画以来、関数型言語を扱っていません。私はそれを好まないことを、その仕事にチャンスがなかっただけで決して、私は私の自由な時間コーディング以上の学習を費やす必要があれば、私だけではなく(TMPのように!)何かを学ぶことではない:)
樹液

@樹液:まあ、あなたは同じ思考モードに入る必要があります...
マッケ

@sap:実際、Schemeはコンパイル時のメタプログラミングに慣れるのに最適な言語かもしれません。そのマクロシステムは、C ++のテンプレートと同様の効果を達成しながら、非常に機能的でエレガントです(ただし、C ++をあまり使用していません)。
Tikhon Jelvis 2011年

2

テンプレートで何かを実行できるからといって、そうする必要があるわけではありません。設計するときに、これがテンプレートにとって素晴らしい仕事だと思わない限り、実用的には、テンプレートを使用しない方が良いでしょう。テンプレートをよく考えすぎると、1つの巨大な関数と同じくらいひどい抽象的なめちゃくちゃなコードが作成されてしまいます。


答えのためのおかげで、はい私はそれを理解し、私はちょうど:)学びたい
樹液

上記に同意します。テンプレートを使用した場合、それは通常、既存のコードをリファクタリングした結果です。元のコードを新しい方法で使用すると、テンプレートは元のコードの改善としてより明確に表示されます。既知のユースケースを取得する前に、設計を行うときにテンプレートが有用かどうかを判断するのは困難です。
Sam Goldberg

2

テンプレートが最良のソリューションであることは非常にまれであることを覚えておいてください。私は過去5年間に1回だけ自分自身を定義しましたが、そのコードをレビューした同僚はそれを行ったことはありませんでした。テンプレートが多くの意味をなすケースは、ほとんどすでに標準ライブラリに実装されています。

一般的なプログラミングでは、定数や型などの小さな変更のみを行うために関数をコピーして貼り付けているため、継承や関数パラメーターなどを使用して繰り返しを避けるための明確な方法を理解できないことに注意してください。あなた自身。

テンプレートが使用されるかなり一般的な方法の1つは、同じように動作する型があるが、何らかの理由で誤ってそれらを混同させたくない場合に、型の安全性を確保することです。

テンプレートを使用したコンパイル時の計算では、コンパイル時にすべての入力がわかっているが、コード全体のさまざまな場所でさまざまな定数入力が使用されているリソース集約型の計算に注意する必要があります。ただし、これによりコンパイルが毎回遅くなることに注意してください。頻繁に変更されない場合は、結果を手動でハードコーディングすることをお勧めします。

一部の支持者は、静的ポリモーフィズムを使用した仮想テーブル検索の回避などのマイクロ最適化やループのアンロールなどにテンプレートを使用しますが、私の意見では、コードが非常にパフォーマンスクリティカルでない限り、通常、複雑さはパフォーマンスの向上を上回ります。


回答ありがとうございます。これらの点に留意してください。私はそれをすべてに使用できないことを知っています(誰かが前に言ったように、すべてを「ネイル」として見ることはできません)。TMPがライブラリ開発に優れていることを正しく理解している場合(C ++全体がそうです)、これを学ぶためだけでなく、これから作成するすべての製品コードに適用します。5年に1回すごい?TMPがコードを本当に改善できる方法を示していると思います。
SAP

2

基本的に、テンプレートを使用する理由はいくつかあります。

  1. 異なる型に対して同じ機能を持つ関数またはクラスがあります。テンプレートの適切な使用例は、Boost Libraryです。
  2. 静的なポリモーフィズムを使用し、ランタイムエラーではなくコンパイルエラーを取得する
  3. いくつかの静的パラメーターに応じて特定の動作を取得したい。たとえば、boost :: type_traitsは非常に優れた例を提供します。

ありがとう!以前に使用されていたタイプの特性、本当にクールなもの!enable_ifも型特性ですか?それともSFINAEの「状態」ですか?以前(コードレビューで)使用したことがあり、非常に強力に見えましたが、さまざまな問題に適用できませんでした。
SAP

@sapこれはタイプ特性であり、SFINAEを使用して実装できます。
BЈовић

1

C ++でテンプレートを確認する必要があります。これは、デザインパターンやジェネリックプログラミングなどのトピックを理解するのに大いに役立ちます。他の言語で提供されているものと比較してください。具体的には、特に次のシナリオでテンプレートを使用する必要があります。

  1. 汎化とコードの再利用
  2. 柔軟性
  3. 時間と予算の制約
  4. 特定のタスクに関する専門知識の欠如

ここにあなたのための良いオンラインリソースがあります:http : //en.wikipedia.org/wiki/Generic_programming#Templates_in_C.2B.2B


与えられた問題にその知識を適用する方法だけでなく、それをどのように使用できるかを知っていますが、それでも良い読書のおかげです:)
sap

1

テンプレートがコードを改善する時期を示す簡単な指標は、コードでオブジェクトを別の型にキャストする必要が頻繁にある場合です。自分のJavaコードで見つけた例で、既存のメソッドシグネチャをテンプレートに変換するきっかけになりました。

    public MsgBase getLastSentMessage(Class<? extends MsgBase> msgBaseClass)

私のクライアントコードは常に次のようになりました。

    OrderResponse response = (OrderResponse) getLastSentMessage(OrderResponse.class);

そして、そのメソッドを使用するときはいつでも、結果をMsgBaseタイプの正しいサブクラスにキャストする必要がありました。改善されたメソッドシグネチャは次のとおりです。

    public <T extends MsgBase> T getLastSentMessage(Class<T> clazz)

現在、クライアントコードは次のとおりです。

     OrderResponse response = getLastSentMessage(OrderResponse.class);

要約すると、不必要に思われるキャストを大量に実行していることに気付いた場合、テンプレートがコードをクリーンアップする良いケースがあるかもしれません。

更新:上記のステートメントを一般化するより良い方法:

ソースクラスが多くの異なるタイプのオブジェクトによって使用され、ソースクラスがそれらのタイプとより高い(より抽象的な)レベルで対話できるが、クライアントクラスが特定のサブタイプと対話したい場合(テンプレートを使用する場合) 。(よく知られている例であるContainer / Listクラス)。


これは非常に興味深く、TMPをそのように適用することを考えたことはありません。それを本当によく学び、さらに練習する必要があることを示すためだけに行きます。
SAP

私はまだここで反対票を見つけようとしています。私は直接質問に答え、テンプレートがリファクタリングから発生する具体的な例を提供しました。それで何が悪かったのですか?
Sam Goldberg

0

ちょうど今日、私はテンプレートを使用して有限状態機械を実装し、入力を抽出しました。式テンプレートは、そのようなコード概念を実装するための非常に強力なツールです。これらは、手作業で最適化されたC ++のように実行され、卑劣に高速ですが、非常に汎用的で、非常に簡単に記述できます。

一般的に言えば、テンプレートは一般的なアルゴリズムを実装するときに最も意味があります。一般的なアルゴリズムを実装していない場合は、それほど意味がありません。


0

テンプレートの最も一般的な用途は次のとおりです。

std::vector<int> vec;
std::map<int, float> mymap;

次に一般的な例は次のとおりです。

template<class T>
class MyArray {
public:
   virtual T get(int i) const=0;
};

この種の使用法とともに:

class ArrayImpl : public MyArray<float> {
public:
     float get(int i) const { }
};

これは、テンプレートの重要な部分、つまり型の置換を示しています。Tは、使用される両方の場所で浮動小数点型に置き換えられます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.