我如何使我的对象重新解释为数组,如std :: complex? [英] How can I make my objects reinterpret-castable to arrays, like std::complex?

查看:261
本文介绍了我如何使我的对象重新解释为数组,如std :: complex?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我刚刚学习了这一点,因为这个问题,标准规定 std :: complex (26.4 [complex.numbers]):


4如果 z cv std :: complex< T> 类型的左值表达式:

- code> reinterpret_cast< cv T(&)[2]>(z)必须格式正确,

- reinterpret_cast< cv T(&)[2](z)[0] 应指定 z 的实部, b $ b- reinterpret_cast 应指定 / code>。

此外,如果 a cv std :: complex< T> * 并且表达式 a [i] 是明确定义的整数表达式 i ,则:

- reinterpret_cast< cv T *>(a)[2 * i] 部分 a [i]

- reinterpret_cast< cv T *>(a)[2 * i + 1] 应指定 a [i] 的虚部。



b $ b

这是我真正想以符合标准的方式利用的方法。有时我有POD,像数学向量,它们由单一的数据类型组成。这里有两个示例类:

  template< typename T,unsigned N> 
struct Vector
{
T v [N];
};

template< typename T>
struct四元数
{
T r,i,j,k;
};



根据我的理解,实现允许在最后一个成员之后添加填充,成员。这意味着 sizeof(Quaterntion< float>)可能不等于 sizeof(float [4]) c $ c> sizeof(Vector< double,8>)
可能不等于 sizeof(double [8])。这意味着我通常必须添加一些 static_assert 到我的代码,以确保我可以投入我的向量< float,N> / Quaterntion< float> float * ,而不必担心填充到C库或OpenGL缓冲区)。



标准提供了一些方法,这将允许我对我的小POD有相同的保证, code>作为 std :: complex 的??我知道实现特定的事情,如 __ attribute __((packed))。我正在寻找一个非实施具体,标准符合的方式做到这一点。因为标准需要支持这种类型的实现提供 std :: complex ,我想知道是否还有一些标准的方式应用此保证到我自己的类。

解决方案

我认为你在问不可能。



记住标准库实现者通常依赖于非标准扩展或实现定义的行为。事实上,在VC ++的复杂头文件中,我们发现:

  #pragma pack(push,_CRT_PACKING)

/ / implementation

#pragma pack(pop)

你的Quaternion是把所有的成员放在数组中,因为struct地址可以被reinterpret_cast指向第一个成员的指针。但我猜这种结构的目的(直接成员访问的名称)。



这不是你要求的,但提供一个

 运算符const T *()const //可以用便携式方式写

为您的结构,将允许您写

  Quaternion< ; double> q = {}; 
const double * p = q;

以额外的运行时/内存开销为代价,具体取决于实现转换运算符的方式。 p>

I just learned this because of this question, that the standard states for std::complex (26.4 [complex.numbers]):

4 If z is an lvalue expression of type cv std::complex<T> then:
— the expression reinterpret_cast<cv T(&)[2]>(z) shall be well-formed,
reinterpret_cast<cv T(&)[2]>(z)[0] shall designate the real part of z, and
reinterpret_cast<cv T(&)[2]>(z)[1] shall designate the imaginary part of z.
Moreover, if a is an expression of type cv std::complex<T>* and the expression a[i] is well-defined for an integer expression i, then:
reinterpret_cast<cv T*>(a)[2*i] shall designate the real part of a[i], and
reinterpret_cast<cv T*>(a)[2*i + 1] shall designate the imaginary part of a[i].

This is something I really want to take advantage of in a standards-conforming manner. There are times when I have PODs, like mathematical vectors, which are composed of a single data type. Here are two example classes:

template <typename T, unsigned N>
struct Vector
{
    T v[N];
};

template <typename T>
struct Quaternion
{
    T r, i, j, k;
};

From what I understand, the implementation is allowed to add padding after the last member, as well as between members. Which means that sizeof(Quaterntion<float>) may not equal sizeof(float[4]), and sizeof(Vector<double, 8>) may not equal sizeof(double[8]). This means I typically have to add some static_asserts to my code to make sure that I can cast my Vector<float, N>/Quaterntion<float> to a float*, for example, and not worry about padding (for passing to C libraries or OpenGL buffers, for example).

Is there some method provided by the standard that would allow me to have the same guarantees for my little PODs, like Vector and Quaternion, as std::complex does? I'm aware of implementation-specific things, like __attribute__((packed)). I'm looking for for a non-implementation specific, standards conforming way of doing this. Since the standard requires support for this type of thing for implementations that provide std::complex, I'm wondering if there's also some standard way of applying this guarantee to my own classes.

解决方案

I think you are asking the impossible.

Keep in mind that standard library implementors often rely on non-standard extensions or implementation-defined behavior. Indeed, in VC++'s complex header we find:

#pragma pack(push, _CRT_PACKING)

// implementation

#pragma pack(pop)

What you could do for your Quaternion is to place all the members inside an array, since the struct address can be reinterpret_cast to a pointer to the first member. But I guess that kind of defeats the purpose of the struct (direct member access by name).

It is not exactly what you ask for, but providing an

operator const T*() const // can be written in a portable manner

for your struct, will allow you to write

Quaternion<double> q = {};
const double * p = q;

at the cost of additional runtime/memory overhead, depending on how you implement the conversion operator.

这篇关于我如何使我的对象重新解释为数组,如std :: complex?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆