我如何使我的对象重新解释为数组,如std :: complex? [英] How can I make my objects reinterpret-castable to arrays, like std::complex?
问题描述
我刚刚学习了这一点,因为这个问题,标准规定 std :: complex
(26.4 [complex.numbers]):
4如果
z
是 cvstd :: complex< T>
类型的左值表达式:
- code> reinterpret_cast< cv T(&)[2]>(z)必须格式正确,
-reinterpret_cast< cv T(&)[2](z)[0]
应指定z
的实部, b $ b-reinterpret_cast
应指定 / code>。
此外,如果a
是 cvstd :: 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> $ c例如,$ c> /
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 cvstd::complex<T>
then:
— the expressionreinterpret_cast<cv T(&)[2]>(z)
shall be well-formed,
—reinterpret_cast<cv T(&)[2]>(z)[0]
shall designate the real part ofz
, and
—reinterpret_cast<cv T(&)[2]>(z)[1]
shall designate the imaginary part ofz
.
Moreover, ifa
is an expression of type cvstd::complex<T>*
and the expressiona[i]
is well-defined for an integer expressioni
, then:
—reinterpret_cast<cv T*>(a)[2*i]
shall designate the real part ofa[i]
, and
—reinterpret_cast<cv T*>(a)[2*i + 1]
shall designate the imaginary part ofa[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_assert
s 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屋!