将 T 数组别名为 std::complex<T> 数组合法吗?

Is aliasing an array of T to an array of std::complex<T> legal?

我知道严格的 type-aliasing 规则。但是,cppreference 注意到

An implementation cannot declare additional non-static data members that would occupy storage disjoint from the real and imaginary components and must ensure that the class template specialization does not contain any padding. The implementation must also ensure that optimizations to array access account for the possibility that a pointer to value_type may be aliasing a std::complex specialization or array thereof.

此要求是否允许像下面这样的代码是合法的,即使它不一定是道德的?

std::size_t numDoubles = 100;
double* a = (double*) std::malloc(numDoubles * sizeof(double));
std::complex<double>* b = reinterpret_cast<std::complex<double>*>(a);
DoSomethingWith(b[1]);

如果使用 new[] 生成 array-of-double,答案会改变吗?

XY 问题说明:我正在尝试对可能不存在的 third-party 库提供的分配器进行抽象;该分配器 returns a void*;我试图避免 does-the-library-exist 细节泄漏到 header 中。所以我有如下结构:

// foo.h
namespace impl {
    void* Allocate(std::size_t numBytes);
}

template<typename T>
T* Allocate(std::size_t num) {
    static_assert(std::is_pod_v<T>);
    return static_cast<T*>(Allocate(num * sizeof(T)));
}


// foo.cpp
#if LIBRARY_PRESENT

void* impl::Allocate(std::size_t numBytes) { return LibraryAllocate(numBytes); }

#else

void* impl::Allocate(std::size_t numBytes) { return std::malloc(numBytes); }

#endif

不幸的是,std::complex 不是 POD,因为它有一个 non-trivial 默认构造函数。我希望我可以忽略这个问题。

Does this requirement allow code like the following to be legal

即使您直接使用 a 而不是转换为 complex,该代码也不严格合法。 C++ 对象模型不允许您只获取一些内存,将其转换为一个类型,然后假装对象存在于该内存中。无论类型如何(字节类型之外)都是如此。

该代码永远不会创建 double 的数组,因此您无法像访问 double 的数组那样访问内存。您也无法访问 complex<double>,就好像它就在那里一样。

Does the answer change if new[] is used to generate the array-of-double?

只有在double的合法数组的意义上才会存在。那里仍然没有complex<double>

std::complex<T>提供的规则是you can access its members as though it were an array of two Ts。这确实 而不是 意味着您可以访问任何两个 T 的数组,就好像它是 std::complex<T>.

所以标准部分 [complex.numbers]p4 说如下:

If z is an lvalue of type cv complex then:

  • the expression reinterpret_­cast(z) shall be well-formed,
  • reinterpret_­cast(z)[0] shall designate the real part of z, and
  • reinterpret_­cast(z)[1] shall designate the imaginary part of z.

Moreover, if a is an expression of type cv complex* and the expression a[i] is well-defined for an integer expression i, then:

  • reinterpret_­cast(a)[2*i] shall designate the real part of a[i], and
  • reinterpret_­cast(a)[2*i + 1] shall designate the imaginary part of a[i].

它没有为 strict aliasing rule 开辟出一个例外,所以看起来通过 double[=21= 别名 std::complex<double> 是无效的].

使用 new 不会改变分析。