In various 3d math codebases I sometimes encounter something like this:
struct vec {
float x, y, z;
float& operator[](std::size_t i)
{
assert(i < 3);
return (&x)[i];
}
};
Which, AFAIK is illegal because implementations are allowed to spuriously add padding between members, even if they are of the same type, though none will do so in practice.
Can this be made legal by imposing constraints via static_assert
s?
static_assert(sizeof(vec) == sizeof(float) * 3);
I.e. does static_assert
not being triggered implies operator[]
does what is expected and doesn't invoke UB at runtime?
No, it is not legal because when adding an integer to a pointer, the following applies ([expr.add]/5):
If both the pointer operand and the result point to elements of the same array object, or one past the last element of the array object, the evaluation shall not produce an overflow; otherwise, the behavior is undefined.
y
occupies the memory location one past the end of x
(considered as an array with one element) so adding 1 to &x
is defined, but adding 2 to &x
is undefined.
Type aliasing (use of more then one type for essentially the same data) is a huge problem in C++. If you keep member functions out of structs and maintain them as PODs, things ought to work. But
static_assert(sizeof(vec) == sizeof(float) * 3);
can't make accessing one type as another technically legal. In practice of course there will be no padding, but C++ isn't clever enough to realise that vec is an array of floats and an array of vecs is an array of floats constrained to be a multiple of three, and the casting &vecasarray[0] to a vec * is legal but casting &vecasarray[1] is illegal.
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