6

ウィキペディア (ここ) は、for ループのコンパイル時のアンロールを提供します........内部のテンプレート ステートメントで同様の for ループを使用できるかどうか疑問に思っていました...たとえば...

次のループは有効ですか

template<int max_subdomain>
void Device<max_sudomain>::createSubDomains()
{
    for(int i=0; i< max_subdomain; ++i)
    {
        SubDomain<i> tmp(member);
        ...
        // some operations on tmp
        ...
    }
}

SubDomain は、テンプレート パラメーター int を受け取るクラスであり、ここでは Device クラスのメンバーである引数を使用して構築されています。

答えてくれてありがとう...私が欲しいものを知ったので...とにかく私がやりたいことを達成できますか??

私はついに欲しいものを手に入れました........ forループを直接使用する代わりに...代わりにBoost::MPL for_eachコンストラクトを使用できます。私はまだそれを実装していませんが、これは私が望んでいたことを行う方法を提供すると推測しています.....

ここで別のスタックオーバーフローの質問から回答を取りました...ただし、同じ質問へのコメントは、非常に遅くなるため(もちろん大きなforループの場合)、その使用を非難しています...しかし..大きくないforループi膨満感があるべきではないと思います...コードを試して、結果をお知らせします....

使用法は例でよく説明されています

4

3 に答える 3

8

これには標準的な解決策があります。反復を再帰に変換します。

template<int i>
void Device::createSubDomains()
{
    SubDomain<i> tmp(member);
    // some operations on tmp
    createSubDomains<i-1>();
}
template<>
void Device<-1>::createSubDomains()
{
  // End of recursion.
}

注: runtime は使用できませんif(i!=0) createSubDomains<i-1>();

2017 注: コンパイル時を使用できるようになりましたif constexpr(i!=0) createSubDomains<i-1>();

于 2011-07-19T09:09:48.637 に答える
2

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
}


概要

したがって、人間が読める形式では、型ではなく(整数)値であるテンプレート引数は、コンパイル時定数でなければなりません。

  • コンパイル時定数の初期化子には、他のコンパイル時定数のみが含まれている必要があります
  • リテラル値はコンパイル時定数です
  • 列挙値はコンパイル時定数です
  • 関数呼び出しはコンパイル時定数を与えません(いくつかの高度な理由により)
于 2011-07-19T10:13:48.517 に答える
0

再編集:

私の前の答えは正しかった。コードを試してみましたが、コンパイラ エラーが発生しています。そのようにオブジェクトを宣言することはできませiん。コンパイル時の定数のままにすることはできません(意図しているように i++)。templateパラメータは常にコンパイル時の定数でなければなりません。これがデモです。

また、コンパイラによる最適化の一環として、通常のループに対してもループ展開が行われることに注意してください。Sに限ったことではありませんtemplate

于 2011-07-19T04:51:50.003 に答える