2013-08-27 9 views
5

私はGCC 4.8で正常にコンパイルしているようだ打ち鳴らす3.3でいくつかのコードをコンパイルしています:打ち鳴らす3.3とconstexprの制約

オリジナルのコードだった:打ち鳴らすには

template <std::size_t N> struct helper { typedef void type; }; 
template <> struct helper<64> { typedef int64_t type; }; 
template <> struct helper<32> { typedef int32_t type; }; 
template <> struct helper<16> { typedef int16_t type; }; 
template <> struct helper<8> { typedef int8_t type; }; 

template <std::size_t I, std::size_t F> 
struct test 
{ 
    typedef typename helper<I+F>::type value_type; 
    static constexpr std::size_t frac_mask = ~((~value_type(0)) << F); 
}; 

、私は宣言しようとすると、私がコードを変換する場合、それで遊んで

test.cpp:41:34: error: constexpr variable 'frac_mask' must be initialized by a constant expression

static constexpr std::size_t frac_mask = ~((~value_type(0)) << F); 

:テスト< 16,16>またはテスト< 8,0>は、私はエラーを取得する

template <std::size_t I, std::size_t F> 
struct test 
{ 
    typedef typename helper<I+F>::type value_type; 
    typedef typename std::make_unsigned<value_type>::type mask_type; 

    static constexpr mask_type frac_mask = ~((~mask_type(0)) << F); 
}; 

それはほとんどの場合(I、Fの値)でコンパイルが、私はテスト< 8、0>を宣言した場合、私はエラーを取得する:

test.cpp:23:36: error: constexpr variable 'frac_mask' must be initialized by a constant expression

test.cpp:66:15: note: in instantiation of template class 'test<8, 0>' requested here

test.cpp:23:66: note: left shift of negative value -1

static constexpr mask_type frac_mask = ~((~mask_type(0)) << F); 

私の質問は - いくつかのルールがあります私はconstexprの仕様の点でここに違反していますか?また、最後のエラー - マスク型はunsignedです - これは私が負の値をシフトしていると思うか、コードを誤読していると思うコンパイラの問題ですか?

+0

[テンプレートのデフォルト引数でconstexprを呼び出す]の複製が可能です(http://stackoverflow.com/questions/10721130/calling-constexpr-in-default-template-argument) –

+0

uint8_tをintに変換するタイプのプロモーションルール。署名されていますか? –

答えて

3

最初のケースでは、署名付きオーバーフローが発生しています。 C++ 11 5.19/2に列挙された定数式であると表現ないのための条件の一つは、それは剰余演算を使用するように定義された符号なしのタイプを使用して

a result that is not mathematically defined or not in the range of representable values for its type

を含むことです結果は範囲内にとどまります。おそらく、GCCはClangよりもこのルールに関して厳格ではありません。

最終的には、符号なし8ビット型が符号なし型ではなくintに昇格されるため、再び符号付きオーバーフローが発生します。私はそのことについてかなりよく分からないが、

static constexpr mask_type frac_mask = ~(mask_type(~mask_type(0)) << F); 

、としてテストするためのクランをインストールしていない:あなたはおそらく否定した後、符号なしの型に戻す変換していることを修正することができます。

+0

それはそれを修正するようだ - あなたは私に説明することができますなぜビットなしでは、符号なしタイプのintに昇格されるのだろうか? – user2721897

+0

@ user2721897:プロモーションルールでは、元のタイプのすべての値を表すことができる場合は、プロモートルールによって「int」にプロモートされます。より小さな型の場合は、符号付きまたは符号なしの場合です。 –

+0

@ user2721897符号なしのcharは、〜(または任意の算術演算子)が適用される前にint *に昇格されます。これは例えば'intvar greggo

関連する問題