2013-08-27 8 views
5

ich einige Codes mit Klirren 3.3 kompilieren, die 4.8 mit gcc zu kompilieren fein scheint:Klirren 3.3 und constexpr Einschränkungen

Der ursprüngliche Code war:

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); 
}; 

In Klirren, wenn ich versuchen zu erklären, Test < 16,16> oder Test < 8,0> ich erhalte den Fehler:

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); 

Spiele, um mit ihm, wenn ich den Code zu konvertieren:

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); 
}; 

Es kompiliert in den meisten Fällen (Werte von I, F), aber wenn ich Test erklären < 8, 0>, erhalte ich die Fehlermeldung:

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); 

Meine Frage ist - gibt es einige Regeln Ich verstoße hier in Bezug auf die Spezifikation von conetexpr? Auch für den letzten Fehler - Maskentyp ist unsigned - ist dies ein Compiler-Problem, dass es denkt, dass ich einen negativen Wert verschiebe oder bin ich den Code falsch lesen?

+0

möglich Duplikat [Aufruf constexpr in Template-Argument default] (http://stackoverflow.com/questions/10721130/calling-constexpr-in-default-template-argument) –

+0

Typ Förderung Regeln Ihre uint8_t Umwandlung in int, die ist unterschrieben? –

Antwort

3

Im ersten Fall verursachen Sie einen signierten Überlauf. Eine der Bedingungen für einen Ausdruck nicht ein konstanter Ausdruck ist, aufgelistet in C++ 11 5,19/2, ist, dass es

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

Durch die Verwendung eines unsigned Typ beinhaltet, die modulare Arithmetik definiert ist, zu verwenden, , das Ergebnis bleibt in Reichweite. Vermutlich ist GCC bezüglich dieser Regel weniger streng als Clang.

Im letzten Fall wird der vorzeichenlose 8-Bit-Typ auf int hochgestuft, kein vorzeichenloser Typ, sodass Sie erneut signierten Überlauf erhalten. Sie können sich wahrscheinlich beheben, die durch nach negiert zurück zum Typ ohne Vorzeichen Umwandlung:

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

obwohl ich bin mir nicht ganz sicher, dass, und keine Clang Installation mit zu testen.

+0

Das scheint es zu beheben - können Sie mir erklären, warum bitweise nicht von einem vorzeichenlosen Typ zu int hochgestuft würde? – user2721897

+0

@ user2721897: Die Heraufstufungsregeln geben an, dass sie auf "int" hochgestuft werden, wenn dies alle Werte des ursprünglichen Typs darstellen kann. Das ist bei jedem kleineren Typ der Fall, signiert oder unsigniert. –

+0

@ user2721897 Das Zeichen ohne Vorzeichen wird nach int * vor * heraufgesetzt, wobei der ~ (oder ein beliebiger arithmetischer Operator) angewendet wird. Dies bedeutet, dass z.B. 'intvar greggo

Verwandte Themen