"cast to first member of standard layout" 类型双关规则是否扩展到数组?

Does the "cast to first member of standard layout" type punning rule extend to arrays?

具体来说,我将 C API 包装在一个友好的 C++ 包装器中。 C API 有这个相当标准的形状:

struct foo {...};
void get_foos(size_t* count, foo* dst);

喜欢 做的是,通过将类型化双关包装器 array 直接传递给C api 进行了一系列完整性检查 static_assert().

class fooWrapper {
  foo raw_;
public:
   [...]
};

std::vector<fooWrapper> get_foo_vector() {
  size_t count = 0;
  get_foos(&count, nullptr);

  std::vector<fooWrapper> result(count);

  // Is this OK?
  static_assert(sizeof(foo) == sizeof(fooWrapper), "");
  static_assert(std::is_standard_layout<fooWrapper>::value, "");
  get_foos(&count, reinterpret_cast<foo*>(result.data()));

  return result;
}

我的理解是它是有效代码,因为所有访问的内存位置都单独符合规则,但我想确认一下。

编辑: 显然,只要 reinterpret_cast<char*>(result.data() + n) == reinterpret_cast<char*>(result.data()) + n*sizeof(foo) 为真,它就会 在当今所有主要编译器下工作 。但我想知道标准是否同意。

首先,这不是双关语。您正在做的 reinterpret_cast 只是一种改写的 &result.data().foo_ 方式。类型双关是通过 pointer/reference 访问一种类型的对象到另一种类型。您正在访问其他类型的子对象。

其次,这行不通。 Pointer arithmetic is based on having an array(出于指针运算的目的,单个对象充当 1 个元素的数组)。并且 vector<T> 由 fiat 定义以产生一个 T 的数组。但是 T 的数组并不等同于 T 的某个子对象的数组,即使该子对象与 T 的大小相同并且 T 是标准布局。

因此,如果get_foos对其给定的foo数组执行指针运算,那就是UB。哦,当然,它几乎肯定 有效 。但是语言的答案是UB。