14

c ++テンプレートメタプログラミングは関数型プログラミングの一形態ですか?もしそうなら、c ++テンプレートメタプログラミングに関連する非末尾再帰のスタックオーバーフローのようないくつかの落とし穴はありますか?

この質問の階乗テンプレートの例では、標準の関数型プログラミングだと思います。または、類似性は表面的なものにすぎませんか?

#include <iostream>
using namespace std;

template< int n >
struct factorial { enum { ret = factorial< n - 1 >::ret * n }; };

template<>
struct factorial< 0 > { enum { ret = 1 }; };

int main() {
    cout << "7! = " << factorial< 7 >::ret << endl; // 5040
    return 0;
}
4

3 に答える 3

9

c ++テンプレートメタプログラミングは関数型プログラミングの一形態ですか?

うん!テンプレートの拡張には副作用がないため、純粋に機能します。

もしそうなら、c ++テンプレートメタプログラミングに関連する非末尾再帰のスタックオーバーフローのようないくつかの落とし穴はありますか?

絶対。スタックがオーバーフローするずっと前に結果がオーバーフローするため、Factorialはこれの良いデモンストレーションではありませんが、再帰が長いとコンパイラがエラーになる可能性があります。ただし、興味深いことに、コンパイラーは、自動メモ化を取得するような方法でテンプレートを実装する傾向があります。たとえば、フィボナッチ数列の素朴に書かれた実装は、O(2 ^ n)ではなくO(n)時間でコンパイルされる傾向があります。

于 2017-03-10T12:39:58.790 に答える
7

最良の答えは、2つの概念が完全に異なるものであるということだと思います。しかし、それは実際には役に立たないので、ここに私が考えることができるいくつかの重要なポイントがあります:

  • C ++テンプレートとMLのような関数型言語(のパラメトリックポリモーフィズム)はどち​​らもジェネリックプログラミングの例であるため、1つの質問でそれらを一緒に言及することは理にかなっています。アカデミアでは、ジェネリックプログラミングに関するワークショップでさえ、C++テンプレートやMLスタイルの関数型プログラミングをカバーすることがよくあります。

  • ただし、テンプレートメタプログラミングを使用すると、C ++コードのコンパイル中に「評価」されるコードを記述できるため、非常に限られたタスクにのみ使用できます。一方、機能プログラムは通常、実行時に実行され、複雑なデータ構造を定義したり、抽象化を構築したりできます(テンプレートメタプログラミングを使用していくつかのことを実行できますが、見栄えが悪くなります)。

  • 階乗の例が関数型プログラミングの階乗に似ているのはなぜですか?テンプレートメタプログラミングを使用している場合、「可変変数」を定義することはできません(新しいタイプまたはテンプレートを定義しているだけなので)。そのため、テンプレートメタプログラミングは関数型プログラミングスタイルのように感じるかもしれません。

  • テンプレートメタプログラミングを使用して記述されたコードは、コンパイル時に評価されます。これは、ユーザー入力に依存できないことを意味します。コンパイルするかどうかのどちらかです(コンパイラーは再帰の深さに制限があり、しばらくするとあきらめる可能性があります)。一方、関数型プログラムは、入力を受け取ってから評価することができます(つまり、使用可能なすべてのスタックまたはメモリを使用して失敗する可能性があります)。

関数型プログラマーにとって、Agdaのようないくつかの関数型言語もコンパイル時に物事を評価できることを私は知っていますが、物事を単純に保つ方が良いと思います!

于 2012-07-12T23:32:01.720 に答える
0

テンプレートメタプログラミングは、理論的には純粋関数指向の言語です。つまり、関数は、グローバルまたはローカルの状態に関係なく、引数にのみ依存します。ただし、フレンドインジェクションを使用してメタプログラミング状態をキャプチャおよび取得できるようです。したがって、関数はグローバル/ローカルのメタプログラミング状態に応じて異なる結果を返す可能性があります。

于 2021-08-30T08:55:20.143 に答える