Search code examples
c++language-lawyerstrict-aliasingtype-punningstructure-packing

Reinterpret struct with members of the same type as an array in a standard compliant way


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_asserts?

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?


Solution

  • 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.