コンパイル段階でのテンプレートマジックまたは因子計算

こんにちは、Habralyudi!



C ++の第一人者、およびテンプレートのメタプログラミングを知っている人々は、このトピックを安全にスキップできます。 ただし、見出しを読んだ後でもこの問題の解決策が得られない場合(および、テンプレートの助けを借りずにそれが生じた場合でも)、catの下で歓迎されます。





実際には、問題の解決策:

#include <iostream> template<int n> class Factorial { public: static const int f = Factorial<n - 1>::f * n; }; template<> class Factorial<0> { public: static const int f = 1; }; int main() { std::cout << Factorial<5>::f << std::endl; // 120 }
      
      







何が何なのか見てみましょう。 第一に、一部の人は尋ねるかもしれません-コンパイル段階で値が計算されるのはなぜですか? 答えは、C ++のテンプレートの基礎です。 テンプレートが実際にパラメーター化されたタイプに応じて、コンパイル段階で特殊なコードが生成されます。 一番下の行は、たとえば、最低2つの値を返す関数テンプレートを使用する場合です。

 template<class T> const T& min(const T& a, const T& b) { return (a < b) ? a : b; }
      
      





次に、プログラムで使用する場合、例えば:

 min(2, 3)
      
      





タイプintの特殊化のみ生成されます。 そして、あなたが書くなら、次のようなものです:

 min(2.0, 3.0)
      
      





それはdoubleの特殊化を生成します。



さて、階乗に戻ると、階乗<5>テンプレートを生成するために、階乗<4>テンプレートを生成する必要があり、ゼロになります。ここで、階乗<0> :: f( テンプレート<の明示的な特殊化により> )。 この最後のステップは、「再帰的」テンプレート生成を停止し、その後、階乗値自体が計算されます。 コンパイル段階でなぜですか? 定数static const int fはコンパイル時定数であるためです。 誰かがこれを信じていない場合、テンプレートの値を配列の長さとして設定し、プログラムの静かなコンパイルを観察できます。



Bruce Eckelの本Philosophy of C ++。 実用的なプログラミング 。 この問題に対する次の解決策が示されています(本質的には上記と変わりません)。

 template<int n> struct { enum {val = Factorial<n - 1> * n}; }; template<> struct Factorial<0>{ enum {val = 1}; };
      
      







一般に、このような階乗計算は、テンプレートメタプログラミングの特殊なケースです。 たとえば、整数pであるqに累乗すると、ループで記述できます。

 int power = 1; while (q--) power *= p;
      
      







しかし、テンプレートメタプログラミングの助けを借りても可能です。

 template<int p, int q> class Power { public: static const int value = p * Power<p, q - 1>::value; }; template<int p> class Power<p, 0> { public: static const int value = 1; }
      
      







これについての詳細は、例えばEckelの本Philosophy C ++で読むことができます 実用的なプログラミング 、またはAlexandrescuの著書Modern Design in C ++



ご清聴ありがとうございました!



All Articles