【问题标题】:What type will make "std::has_unique_object_representations" return false?什么类型会使“std::has_unique_object_representations”返回 false?
【发布时间】:2017-03-17 10:40:36
【问题描述】:

cppref,我看到一个奇怪的类型特征检查器std::has_unique_object_representations

根据它的描述,我无法想象任何类型的T 使std::has_unique_object_representations<T>::valuefalse

有反例吗?

【问题讨论】:

  • 这里的措辞en.cppreference.com/w/cpp/types/… 暗示 T 需要可以简单地复制并给出一些推理。
  • IEEE 754 兼容的浮点数是一个反例,因为正零和负零的表示不同,但它们的值显然相等。
  • 此外,任何总填充位超过零的类型。

标签: c++ standards c++17 typetraits


【解决方案1】:

理解这个特征的目的需要理解对象“值表示”和它的“对象表示”之间的区别。来自标准:

T 类型对象的对象表示是由T 类型对象占用的 N 个 unsigned char 对象的序列,其中 N 等于 sizeof(T)。对象的 值表示 是一组保存 T 类型值的位。对于普通可复制类型,值表示是对象表示中确定值的一组位,该值是实现定义的一组值的一个离散元素。

因此,对象表示是对象的总存储量。但请考虑以下对象:

struct T
{
  char c;
  int i;
};

在许多系统上,sizeof(T) 将是 8。为什么?因为int 必须是4 字节对齐的,所以编译器在ci 之间插入3 个字节的填充。由于这三个字节是对象存储的一部分(基于sizeof(T)),它们是对象的对象表示的一部分。

但这三个字节不是其值表示的一部分。如果您修改了这些字节,它们不会影响 ci 的值,或与它们相关的任何其他内容。

如果您为T 编写了operator== 重载,则对这些字节的更改不会影响其结果。这也意味着,如果您确实编写了 operator== 重载,它不能像这样实现:

bool operator==(const T &lhs, const T &rhs)
{
  return std::memcmp(&lhs, &rhs, sizeof(T)) == 0;
}

为什么不呢?因为两个Ts 对于这些填充字节可以有不同的值,但仍然具有相同的ci 值。因此它们具有相同的值表示,因此应该被认为是等价的。

has_unique_object_representationsT 的对象表示和它的值表示恰好相互重叠时为真(并且当T 可以简单地复制时)。那么,你什么时候会关心这个呢?

您可以编写一个通用的散列函数,该函数适用于任何可简单复制的类型T,方法是将其值表示形式读取为字节数组并对它们进行散列。好吧,您可以 这样做,但前提是该类型没有填充字节。这就是has_unique_object_representations 告诉你的:对象表示中的所有字节都很重要。

另外,请注意float 类型不一定具有此值,因为在 IEEE-754 中二进制相等和浮点相等不是一回事。所以包含floats 的类型也不一定是这样。实际上,使用补码有符号整数或带有陷阱表示的有符号整数的实现对于此类类型也不会如此。

【讨论】:

  • 我认为您在memcmp 通话中缺少sizeof(T)
  • 那些具有类似浮点行为但属于用户类型的类型呢?我的意思是理论上我可以拥有一个具有一个 uint32 成员但在其上实现所有操作的结构,就好像它是浮动成员一样。换句话说,它将是一个 struct Float{ uint32 f};实现了所有操作,以便 Float 的行为与内置的 float 一样。我也想字符串类不适合这个......
  • @NoSenseEtAl:嗯,这是一个很好的观点,但在许多情况下,TriviallyCopyable 限制会剔除这些限制(如字符串大小写)。毕竟,即使您的 Float::operator== 不会关心某些位,但就语言而言,它们仍然存在并且仍然很重要。
  • 性状名称为什么是复数形式?甚至documentation 也将其描述为 "...如果任何两个具有相同值的 T 类型对象具有相同的对象 representation"
猜你喜欢
  • 2015-12-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-04-12
  • 1970-01-01
  • 2015-02-08
  • 1970-01-01
相关资源
最近更新 更多