enum
他の回答は代替アプローチを十分にカバーしていることがわかりますが、 (またはstatic const int
) が必要な理由を誰も説明していません。
まず、次の非テンプレートの同等物を検討してください。
#include <iostream>
int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n-1);
}
int main()
{
std::cout << Factorial(5) << std::endl;
std::cout << Factorial(10) << std::endl;
}
簡単に理解できるはずです。ただし、階乗の値が実行時に計算されるという欠点があります。つまり、プログラムを実行した後、コンパイラは再帰的な関数呼び出しと計算を実行します。
テンプレート アプローチの考え方は、コンパイル時に同じ計算を実行し、その結果を実行可能ファイルに配置することです。言い換えれば、あなたが提示した例は、似たようなものに解決されます:
int main()
{
std::cout << 120 << std::endl;
std::cout << 3628800 << std::endl;
}
しかし、それを達成するためには、コンパイラを「だまして」計算を実行させる必要があります。そのためには、結果をどこかに保存できるようにする必要があります。
はenum
まさにそれを行うためにあります。そこでうまくいかないことを指摘することで、それを説明しようとします。
通常の を使用しようとしてもint
、非静的メンバーのようなものint
はインスタンス化されたオブジェクトでのみ意味があるため、機能しません。そして、このように値を割り当てることはできませんが、代わりにコンストラクターでそれを行います。プレーンint
は機能しません。
代わりに、インスタンス化されていないクラスでアクセスできるものが必要です。試すことはできますstatic int
が、それでもうまくいきません。clang
問題の非常に簡単な説明が得られます。
c.cxx:6:14: error: non-const static data member must be initialized out of line
static int value=n*Factorial<n-1>::value ;
^ ~~~~~~~~~~~~~~~~~~~~~~~
実際にこれらの定義を行外に配置すると、コードはコンパイルされますが、2 つ0
の が生成されます。これは、この形式が値の計算をプログラムの初期化まで遅らせ、正しい順序を保証しないためです。Factorial<n-1>::value
計算される前に s が取得されたため、0
返された可能性があります。さらに、それはまだ私たちが実際に望んでいるものではありません。
最後に、static const int
そこに置くと、期待どおりに機能します。これstatic const
は、コンパイル時に計算する必要があるためであり、それがまさに私たちが望んでいることです。コードをもう一度入力してみましょう。
#include <iostream>
template <unsigned n>
struct Factorial
{
static const int value=n*Factorial<n-1>::value ;
};
template <>
struct Factorial<0>
{
static const int value=1;
};
int main()
{
std::cout << Factorial<5>::value << std::endl;
std::cout << Factorial<10>::value << std::endl;
}
最初にインスタンス化しますFactorial<5>
。static const int
コンパイラーがその値をコンパイラー時に計算する必要があることを強制します。事実上、Factorial<4>
別の値を計算する必要があるときに型をインスタンス化します。そして、これFactorial<0>
以上インスタンス化せずに値を計算できる場所に到達するまで、これは 1 になります。
それで、それは別の方法と説明でした。コードを理解するのに少しでも役に立てば幸いです。
この種のテンプレートは、最初に投稿した再帰関数の代わりと考えることができます。以下を置き換えるだけです。
return x;
とstatic const int value = ...
、
f(x-1)
とt<x-1>::value
、
- と
if (n == 0)
専門化struct Factorial<0>
。
そして、enum
それ自体については、すでに指摘したように、 と同じ動作を強制するために例で使用されましたstatic const int
。コンパイル時にすべてのenum
値を知る必要があるため、事実上、要求されたすべての値をコンパイル時に計算する必要があるためです。