i
@iammilindの答えはすでに受け入れていますが、別の答えを提案させてください。コンパイル時定数ではない理由についての彼の推論は正しくありませんでした。
あなたが持っているとしましょう
template<unsigned int MAX> struct SubDomain {...};
...
そしてあなたはそれのインスタンスを宣言したい...
SubDomain<i> tmp(member);
次にi
、一般的にいわゆるコンパイル時定数でなければなりません。それは何ですか?
衒学
nontype template argument
標準では、タイプではないテンプレート引数に用語が割り当てられます(D'Oh)。
14.3.2テンプレートの非型引数[temp.arg.nontype]
非型、非テンプレートテンプレートパラメータのテンプレート引数は、次のいずれかである必要があり
ます。—整数型または列挙型の整数定数式。または
— ... [詳細は続きますが、関連性はありません]
右の最初のポイントには、さらなる調査のためのリファレンスが含まれていますan integral constant-expression
。これは私たちを導きます
5.19定数式[expr.const]
いくつかの場所で、C + +は、整数または列挙定数に評価される式を必要とします:配列境界(8.3.4、5.3.4)、ケース式(6.4.2)、ビットフィールド長(9.6)、列挙型初期化子(7.2)、静的メンバー初期化子(9.4.2)、および整数または列挙型の非型テンプレート引数(14.3)として。
次に、重要なのは次のとおりです。
積分定数式には、リテラル(2.13)、列挙子、定数式(8.5)で初期化された積分型または列挙型の静的データ・メンバー、積分型または列挙型の非型テンプレート・パラメーター、および式のサイズのみを含めることができます。
衒学アプリケーション
ループを振り返ると:
for (int i=...
...
SubDomain<i>
そうすれば、そこでは許可されていないことがわかりますi
。なんで?i
ではないのでconst variable
。
観察している読者は、これを回避できると思うかもしれません。
for (int i=...
...
const int I = i;
SubDomain<I>
しかし、これは本当に許可されていますか?負の値は、でI = i
はないため、積分定数式でi
はありません。積分定数式の規則が再帰的に適用されることを理解するのに役立ちます。
たとえば、以下は有効なコードです。
template <int> void foo() {}
int main () {
const int ccI = 0;
const int ccJ = ccI*2;
const int ccK = ccJ/4;
foo<ccK>();
}
しかし、チェーンの一部だけを非定数にすると、ccK
積分定数とは見なされなくなります。
template <int> void foo() {}
int main () {
int ccI = 0;
const int ccJ = ccI*2; // not compile time constant
const int ccK = ccJ/4; // same
foo<ccK>(); // error
}
概要
したがって、人間が読める形式では、型ではなく(整数)値であるテンプレート引数は、コンパイル時定数でなければなりません。
- コンパイル時定数の初期化子には、他のコンパイル時定数のみが含まれている必要があります
- リテラル値はコンパイル時定数です
- 列挙値はコンパイル時定数です
- 関数呼び出しはコンパイル時定数を与えません(いくつかの高度な理由により)