Вы должны будете использовать тип, который может хранить экземпляры одного из типов, которые вы хотите сохранить.
Существует несколько методов, например, варианты.
Одна из возможностей:
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 байта в любом случае.