
Frau
Ich versuche folgenden Code mit zu kompilieren gcc
und C++11
aktiviert:
unsigned int id = 100;
unsigned char array[] = { id % 3, id % 5 };
Ich bekomme diese Warnungen:
Einengende Konvertierung von ‘(id % 3u)’ von ‘unsigned int’ zu ‘unsigned char’ innerhalb von { } [-Wnarrowing]
Online-Demo ansehen
Gibt es eine Möglichkeit, dem Compiler dabei zu helfen, herauszufinden, dass das Ergebnis von Kennung % 3 passt in ein unsigned char?

Shafik Yaghmur
In diesem speziellen Fall machen id
konst oder constexpr wird das Problem beheben:
constexpr unsigned int id = 100;
da es eine Ausnahme für den Fall gibt, wo Sie a haben ständiger Ausdruck dessen Ergebnis nach der Konvertierung in den Zieltyp passt.
Im allgemeineren Fall können Sie auch verwenden static_cast Um das Ergebnis in unsigned char umzuwandeln:
{ static_cast<unsigned char>( id % 3), static_cast<unsigned char>( id % 5) }
^^^^^^^^^^^ ^^^^^^^^^^^
Wir finden die Ausnahme für konstante Ausdrücke und einschränkende Konvertierungen in der Entwurf des C++-Standards Sektion 8.5.4
Listen-Initialisierung was sagt:
Eine einschränkende Konvertierung ist eine implizite Konvertierung
und fügen Sie das folgende Aufzählungszeichen ein (Betonung von mir):
- von einem Integer-Typ oder Aufzählungstyp ohne Bereich zu einem Integer-Typ, der nicht alle Werte des ursprünglichen Typs darstellen kann, außer wenn die Quelle ein konstanter Ausdruck ist, dessen Wert nach ganzzahligen Heraufstufungen in den Zieltyp passt.
Beachten Sie, dass sich der Wortlaut vom ursprünglichen Entwurf des C ++ 11-Standards zu dem geändert hat, was ich oben zitiere Mängelanzeige 1449.

Yakk – Adam Nevraumont
Es ist eine Eigenart von C++, in die fast alle mathematischen Operationen ihre Argumente umwandeln int
.
Hier ist eine Skizze einer Nicht-Verbreiterung %mod%
Operator:
template<class T, class U,class=void> struct smallest{using type=T;};
template<class T, class U>
struct smallest<T,U,std::enable_if_t<(sizeof(T)>sizeof(U))>>{using type=U;};
template<class T,class U>using smallest_t=typename smallest<T,U>::type;
constexpr struct mod_t {} mod;
template<class LHS>struct half_mod { LHS lhs; };
template<class LHS>
constexpr half_mod<std::decay_t<LHS>> operator%( LHS&& lhs, mod_t ) { return {std::forward<LHS>(lhs)}; }
template<class LHS, class RHS>
constexpr smallest_t<LHS, std::decay_t<RHS>> operator%( half_mod<LHS>&& lhs, RHS&& rhs ) {
return std::move(lhs.lhs) % std::forward<RHS>(rhs);
}
Das Ergebnis von a mod b sollte das kleinste der beiden Typen sein, da es nicht größer sein kann. Möglicherweise sollte etwas Arbeit für signiert / nicht signiert erledigt werden, aber ich werde punten und den ersten nehmen.
So id %mod% 3
endet sein char
.
Sie können Folgendes verwenden:
unsigned char array[] = {
static_cast<unsigned char>(id % 3),
static_cast<unsigned char>(id % 5)
};

Bathseba
Als id
ist ein unsigned int
die Art von id % 3
wird auch ein unsigned int
.
Ihr Compiler warnt Sie hilfreich davor unsigned char
(standardmäßig 8 Bit), könnte zu klein sein, um die zu erhalten unsigned int
(was nach dem Standard mindestens 16 Bit ist).
In diesem speziellen Fall wissen Sie es natürlich besser. Benutzen static_cast<unsigned char>(id % ...)
um dem Compiler mitzuteilen, dass die einschränkende Konvertierung sicher ist.
10124400cookie-checkC++11: „Verengung der Konvertierung innerhalb von {}“ mit Modulusyes
static_cast<unsigned char>(id % 3)
?– Borgführer
17. November 2014 um 14:22 Uhr
Können Sie das Ergebnis nicht in einem Array von Ints speichern? Wofür werden Sie es verwenden?
– Neil Kirk
17. November 2014 um 14:36 Uhr