1

メタプログラミング手法を使用してコンパイル時のビットマスクを作成しようとしています。私の考えは、次のようなものを作成することです。

unsigned int Mask3 = Mask<2>(); // value = 0x03 = b00000000000000000000000000000011
unsigned int Mask3 = Mask<3>(); // value = 0x07 = b00000000000000000000000000000111
unsigned int Mask3 = Mask<7>(); // value = 0x7F = b00000000000000000000000001111111

私が試しているコードは次のとおりです。

template <const unsigned int N> const unsigned int Mask()
{
    if (N <= 1)
    {
        return 1;
    }
    else
    {
        return ((1 << N) | Mask<N - 1>());
    }
}

1を返します。

しかし、それは警告のトンのペアになります:

  • 警告C4554:'<<':演算子の優先順位をチェックしてエラーの可能性を確認してください
  • 警告C4293:'<<':シフトカウントが負または大きすぎる

そして最後に、コンパイルエラー:

  • エラーC1202:再帰型または関数依存性コンテキストが複雑すぎます。

したがって、再帰が終了せず、コンパイラの無限ループに陥ることはないと推測しますが、その理由がわかりません。

4

6 に答える 6

4

再帰的である必要はありません。これは問題なく動作するはずです:

template <const unsigned int N> const unsigned int Mask()
{
    return ((1 << N) - 1);
}

本当にテンプレートである必要はありません。(インライン)関数は問題ありません。

Nの任意の値をサポートする場合、具体的N >= sizeof(unsigned int) * CHAR_BITには、それらを特殊なケースとして扱いたい場合があることに注意してください。

于 2012-08-02T13:57:40.910 に答える
4

すでに指摘したように、コンパイル時の再帰を停止するためにランタイムチェックに依存していますが、これは機能しません。さらに重要なのは、おそらく、あなたがやりたいことのために、あなたがそれを呼び出すまで価値がない関数を定義しているということです。したがって、特殊化を使用して再帰を停止した後でも、実行時に呼び出される関数のネストされたシーケンスがあります。

完全なコンパイル時の評価が必要な場合は、クラステンプレートの静的データメンバーを定義する必要があります。これは、コンパイル時定数をテンプレートに表示できる唯一の方法だからです。何かのようなもの:

template <unsigned int N>
struct Mask
{
    static unsigned int const value = (1 << (N - 1)) | Mask<N - 1>::value;
};

template <>
struct Mask<0>
{
    static unsigned int const value = 0;
};

(間違えた数値も修正しました。)

もちろん、これほど複雑なものは必要ありません。以下はトリックを行う必要があります:

template <unsigned int N>
struct Mask
{
    static unsigned int const value = (1 << (N + 1)) - 1;
};

template <>
struct Mask<0>
{
    static unsigned int const value = 0;
};

(まだ0の特殊化が必要です。それ以外の場合、0はすべてのビットが設定されていることを意味します。)

最後に、もちろん:値にアクセスするには、のようなものを書く必要がありますMask<3>::value。(これをマクロでラップすることをお勧めします。)

于 2012-08-02T14:14:19.960 に答える
3

テンプレートはコンパイル時に作成されますが、再帰を停止するために実行時の動作に依存しています。

たとえば、Mask <2>をインスタンス化する場合、Mask <1>を使用し、Mask <0>を使用し、Mask<-1>を使用します。

Nが1未満であるかどうかの実行時チェックがありますが、これはコンパイル時に役立ちません。それでも、関数の無限のシーケンスを作成します。

于 2012-08-02T13:54:59.920 に答える
3

テンプレートのインスタンス化の再帰を鈍らせるには、1つの明示的な特殊化を導入する必要があります。

template <0> const unsigned int Mask()
{
    return 1;
}

コンパイラは両方のifブランチのテンプレート実装を生成しようとするため、再帰は終了しません。したがって、Mask <0>を生成すると、Mask<0xffffffff>なども生成されます。

于 2012-08-02T13:56:55.770 に答える
1

C ++ 11-再帰やテンプレートはありません:

constexpr unsigned mask(unsigned N) { return unsigned(~(-1<<N)); }
于 2012-08-23T12:57:33.173 に答える
1

これまでのところ、回答は2番目のエラー(C1202)のみに対応していましたが、それ以上の質問がありました。

警告C4554は、テンプレートパラメータと<<演算子に関連するMicrosoftコンパイラのバグが原因で発生します。したがって、(1 << N)は警告を生成します。Nが通常のパラメータである場合、もちろん警告はありません。

非常に簡単な回避策は、(1 << N)の代わりに(1 <<(N))を使用することであり、C4554はなくなります。

于 2015-11-13T03:00:23.010 に答える