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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With