2012-03-26 32 views
0

Ich habe ein Problem, das ich nicht lösen kann. Lassen Sie uns sagen, dass ich diese Karte Definition haben:C++ Map Definition Grundlagen

map<string, int16_t> Registers; 

aber manchmal, ich brauche eine nicht signierte int16_t zu speichern, anstatt eines signierten int16_t. Wie kann ich das tun?

Danke.

+0

Haben Sie versucht, 'uint16_t' als zweiten Vorlagentyp für den Container zu verwenden, in dem Sie nicht signierte Ints speichern werden? – Alexander

+0

Hallo Alexander, ich wusste nicht, dass du das kannst. – Kam

+0

@Alexander: Was genau meinst du? Vielleicht ein Erklärungsbeispiel geben? –

Antwort

5

Sie können entweder einen größeren Fisch Typ verwenden, wie int32_t, oder verwenden Sie einen boost::variant.

Ein int32_t können alle Werte speichern, die ein oder int16_tuint16_t kann und es den Unterschied zwischen bewahrt, beispielsweise 32768 und -32768 (Zweier-Komplement vorausgesetzt). Wenn Sie ein Casting-Schema mit int16_t und uint16_t verwendet haben, würde der Unterschied zwischen diesen verloren gehen, da beide als 0x8000 gespeichert werden würden. Wenn Sie Werte von 0x8000 teilen möchten, benötigen Sie Out-of-Band-Informationen, die Sie nicht erwähnt haben.

int32_t wird jedoch nicht den Unterschied zwischen 32767 signiert und 32767 unsigned beibehalten. Wenn das wichtig ist, kann diese Informationen speichern.

+0

lol für die strikeout sehe

+0

Hallo, nun, sagen wir mal ich habe das: map Register; dann, wenn ich einen 16-Bit-Wert speichern, der nicht signiert sein sollte, was ist der Vorteil? Ich meine, wenn ich int16_t dann wenn ich weiß, dass der Wert unsigned ist, ich es einfach werfen? Nein? Ich sehe nicht den Punkt der Verwendung eines 32-Bit-Int – Kam

+0

@ Kam - Alle 16-Bit-Werte, mit oder ohne Vorzeichen, passen in eine "Int32_t". –

3

Sie müssten einen Typ verwenden, der Instanzen eines der Typen speichern kann, die Sie speichern möchten.

Es gibt mehrere Verfahren, z.B. Varianten.

Eine Möglichkeit ist:

class Foo { 
public: 
    enum class Type : char { Int16, Uint16 }; 

    static Foo Int16 (int v)   { Foo ret{Type::Int16}; ret.int16_ = v; return ret;} 
    static Foo Uint16 (unsigned int v) { Foo ret{Type::Uint16}; ret.uint16_ = v; return ret;} 

    int16_t as_int16() const { assert_(Type::Int16); return int16_; } 
    uint16_t as_uint16() const { assert_(Type::Uint16); return uint16_; } 

    Type type() const { return type_; } 

private: 
    Foo (Type type) : type_(type) {} 
    void assert_(Type t) const { if (t != type_) throw "meh"; } 

    union { int16_t int16_; uint16_t uint16_; }; 
    Type type_; 
}; 

Beispiel:

int main() { 
    Foo f = Foo::Int16(4); 
    std::cout << f.as_int16() << '\n'; // okay 
    //std::cout << f.as_uint16() << '\n'; // exception 

    Foo g = Foo::Uint16(4); 
    std::cout << f.as_uint16() << '\n'; // okay 
    //std::cout << f.as_int16() << '\n'; // exception 

    // Switch on its type: 
    switch (g.type()) 
    { 
    Foo::Type::Int16: std::cout << g.as_int() << '\n'; break; 
    Foo::Type::Uint16: std::cout << g.as_uint() << '\n'; break; 
    } 
} 

Dies ist im Grunde ein union die eine Ausnahme auslösen, wenn Sie versuchen, int zu lesen, aber wirklich unsigned int gespeichert; Kinda union das wurde schwer zu benutzen-falsch gemacht.

boost::variant wäre eine andere Option.

Eine dritte Variante, wie bereits von R. Martinho Fernandes erwähnt, wäre die Verwendung eines größeren, signierten Int. Es hängt von Ihrem Anwendungsfall ab, ob Tippfehler relevant sein kann, wenn Sie T speichern und dann als U lesen möchten, wenn Sie Besucher mögen, wenn Sie den Typ überhaupt verfolgen möchten, und so weiter.

Meine gespeicherte Lösung ist auf meinem System 4 Byte groß (wegen der Ausrichtung), ebenso wie eine größere Ganzzahl mit Vorzeichen. Ich denke, weil Sie Ihre Werte in einem Container speichern, wird es nicht möglich sein, die Typ-Tracking während bleiben 2 Bytes zu verpassen, so dass ich denke, Ihr Minimum ist 4 Bytes in jedem Fall.

+0

phrasnel, ich bin so ein newbi, ich werde versuchen zu verstehen, was Sie gerade geschrieben haben und zu Ihnen zurück. Vielen Dank – Kam

+0

Ich denke, dies kann die Absicht des Fragestellers besiegen, eine 16-Bit-Nummer zu speichern. Wenn die 16-Bit-Typen überarbeitet werden, wäre dies bei den meisten PC-Plattformen die Größe eines int + 2, da viele enums in einem int gespeichert sind. Die Verwendung eines signierten 4-Byte-Typs (int/long an den meisten Stellen) wäre in vielerlei Hinsicht besser. Wenn Sie einen bool verwenden, um zu speichern, ob dieser signiert ist und nicht bearbeitet wurde, um 16Bit-Typen zu verwenden, könnten Sie es auf 3 Bytes pro Instanz heruntersetzen. – Sqeaky

+0

@Sqeaky: Aber wegen der Ausrichtung würde es wieder auf 4 gehen. Ich werde die neue explizite Enum-Typisierung von C++ 11 verwenden. –

0

Entweder Sie führen eine Ebene der Indirektion ein (verlieren den gesamten Punkt des Speicherns von int16_t ziemlich), oder Sie benötigen 2 verschiedene Karten. Es sei denn, Sie zielen auf spezialisierte Hardware ab, oder müssen wirklich Platz sparen, sind Sie besser darin, einen direkten int zu speichern. Es wird insgesamt schneller und weniger mühsam sein.

0

Wenn die zwei Typen die gleiche Größe haben, können Sie das unsigned int as und int interpretieren. Achte nur darauf, dass du den Überblick darüber behältst, ob dein Wert signiert oder unsigniert ist. Das kann bedeuten, dass es besser ist, einen größeren Typ zu verwenden, damit du nicht mehr aufzeichnen musst.