C++11: „Verengung der Konvertierung innerhalb von {}“ mit Modulus

Lesezeit: 3 Minuten

Benutzer-Avatar
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?

  • 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

Benutzer-Avatar
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.

Benutzer-Avatar
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.

  • Ich vermute einen kleinen Fehler: operator%( LHS&& lhs, mod ) muss sein operator%( LHS&& lhs, mod_t ). Abgesehen davon: Das funktioniert bei mir nur, wenn ich auf char caste: id %mod% (char) 3ansonsten der 3 wird auch als interpretiert int vom Compiler. Irgendwie drum herum?

    – Frau

    17. November 2014 um 16:03 Uhr


  • @ms bah, ich dachte mir, dass die Konstante a war char nicht ein int. So schrecklich es auch ist, '\3' ist die Zeichenkonstante 3. :/ Wahrscheinlich ist Ihre beste Wette constexpr auf der id wirklich, wenn es wirklich eine Konstante ist.

    – Yakk – Adam Nevraumont

    17. November 2014 um 16:45 Uhr


Sie können Folgendes verwenden:

unsigned char array[] = {
    static_cast<unsigned char>(id % 3),
    static_cast<unsigned char>(id % 5)
};

Benutzer-Avatar
Bathseba

Als id ist ein unsigned intdie 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.

1012440cookie-checkC++11: „Verengung der Konvertierung innerhalb von {}“ mit Modulus

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy