我遇到了无法解决的问题。假设我有这个地图定义:
map<string, int16_t> Registers;
但有时,我需要存储unsigned int16_t而不是signed int16_t。 我怎么能这样做?
感谢。
答案 0 :(得分:5)
您可以使用更大的 fish 类型,例如int32_t
,或使用boost::variant
。
int32_t
可以存储int16_t
或uint16_t
可以存储的所有值,并保留例如32768和-32768之间的差异(假设为2的补码)。如果您使用了int16_t
和uint16_t
的某些投射方案,则它们之间的差异将会丢失,因为两者都将存储为0x8000。告诉像0x8000这样的值将需要带外信息,如果你有,你没有提到。
但是,int32_t
不会保留32767 signed和32767 unsigned之间的区别。如果这很重要,那么boost::variant
可以保留该信息。
答案 1 :(得分:3)
您必须使用可以存储您要存储的某种类型的实例的类型。
存在几种方法,例如变种。
一种可能性是:
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
将是另一种选择。
R. Martinho Fernandes已经提到的第三种变体是使用更大的有符号的int。这取决于你的用例,如果你想允许存储T然后读取为U,如果你喜欢访问者,如果你需要跟踪类型,等等,那么是否允许存储错误,等等。
我的保存,跟踪解决方案在我的系统上是4字节大(因为对齐),因为是一个更大的有符号整数。我认为因为你将值存储在容器中,所以在保留2个字节时不可能错过类型跟踪,所以我猜你的最小值在任何情况下都是4个字节。
答案 2 :(得分:0)
要么引入1级间接(丢失整个存储int16_t的点),要么需要2个不同的映射。除非你瞄准专门的硬件,或者真的需要节省空间,否则你最好直接存储int。它会更快,更轻松。
答案 3 :(得分:0)
鉴于两种类型的大小相同,您可以将unsigned int转换为int和int。只需确保跟踪您的值已签名或未签名的天气,这可能意味着使用更大的类型可能会更好,因此您无需跟踪签名。