Основы определения карты C ++ - PullRequest
0 голосов
/ 26 марта 2012

У меня есть проблема, которую я не могу решить. Допустим, у меня есть это определение карты:

map<string, int16_t> Registers;

но иногда мне нужно хранить неподписанный int16_t вместо подписанного int16_t. Как я могу это сделать?

Спасибо.

Ответы [ 4 ]

5 голосов
/ 26 марта 2012

Вы можете использовать более крупный тип fish , например int32_t, или использовать boost::variant.

int32_t может хранить все значения, которые могут int16_t или uint16_t, и сохраняет разницу между, например, 32768 и -32768 (при условии дополнения до двух). Если бы вы использовали некоторую схему приведения с int16_t и uint16_t, разница между ними будет потеряна, так как оба будут сохранены как 0x8000. Для разметки значений, таких как 0x8000, потребуется внеполосная информация, о которой вы не упомянули.

Однако int32_t не сохранит разницу между 32767 подписанными и 32767 неподписанными. Если это имеет значение, то boost::variant может сохранить эту информацию.

3 голосов
/ 26 марта 2012

Вы должны будете использовать тип, который может хранить экземпляры одного из типов, которые вы хотите сохранить.

Существует несколько методов, например, варианты.

Одна из возможностей:

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

Пример:

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

По сути, это union, который выдает исключение при попытке прочитать intно реально хранится unsigned int;Кинда union, которая была сделана трудной в использовании-неправильной.

boost::variant был бы другим вариантом.

Третий вариант, как уже упоминалось Р. Мартиньо Фернандесом, был быиспользовать больший, подписанный Int.Зависит от опечатки, может ли быть ошибочным вводить текст, если вы хотите разрешить хранить T, а затем читать как U, если вам нравятся посетители, если вам вообще нужно отслеживать тип, и так далее.

Мое решение для сохранения с отслеживанием имеет 4 байта в моей системе (из-за выравнивания), как и большее целое число со знаком.Я думаю, что поскольку вы храните свои значения в контейнере, невозможно пропустить отслеживание типов, оставаясь с 2 байтами, поэтому я предполагаю, что ваш минимум составляет 4 байта в любом случае.

0 голосов
/ 26 марта 2012

Учитывая, что два типа имеют одинаковый размер, вы можете разыграть unsigned int как и int. Просто убедитесь, что вы отслеживаете погоду, если ваше значение подписано или не подписано, что может означать, что может быть лучше использовать больший тип, чтобы вам не приходилось отслеживать подпись.

0 голосов
/ 26 марта 2012

Либо вы вводите 1 уровень косвенности (почти полностью теряя смысл хранения int16_t), либо вам нужно 2 разные карты.Если вы не ориентируетесь на специализированное аппаратное обеспечение или действительно хотите сэкономить место, лучше хранить прямо перед собой int.Это будет быстрее и меньше хлопот в целом.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...