6

I have a struct that represents a vertex. It has x, y and z fields as well as several others. Recently I came into conclusion that for certain functionality I will need to access the coordinates of the vertex as an array. I didn't want to "pollute" the code with temporary variables or change all places that look like this v.y to this v.coord[1] which is not nice nor elegant. So I thought about using a union. Something like this should work:

struct {
  float x,y,z;
} Point;

struct {
    union {
        float coord[3];
        Point p;
    };
} Vertex;

This is good, but not perfect. The point class has no point being there. I want to be able to access y coordinate simply by typing v.y (and not v.p.y).
Can you suggest a hack to solve this (or tell me that it is not possible)?

Artium
  • 5,147
  • 8
  • 39
  • 60

2 Answers2

14

A good C++ approach is to use named accessors that return references to the elements:

class Point {
public:
    float& operator[](int x)       { assert(x <= 2); return coords_[x]; }
    float  operator[](int x) const { assert(x <= 2); return coords_[x]; }

    float& X()       { return coords_[0]; }
    float  X() const { return coords_[0]; }

    float& Y()       { return coords_[1]; }
    float  Y() const { return coords_[1]; }

    float& Z()       { return coords_[2]; }
    float  Z() const { return coords_[2]; }
private:
    float coords_[3];
};

With this approach, given a Point p;, you can use both p[0] and p.X() to access the initial element of the internal coords_ array.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • And maybe also `const float* address() const { return coords_; }` if you'll need to pass it to a C interface. – aschepler Dec 24 '10 at 19:33
  • @aschepler: That could be useful too, though as written, `&p[0]` would yield the same result. – James McNellis Dec 24 '10 at 19:34
  • 2
    +1. And any decent compiler set to optimize will inline those right into place, so it'll be just as efficient as any union hack. – Thanatos Dec 24 '10 at 19:35
  • The problem with your approach is that it needs some changes in the code. what the questioner seems to be interested in is having array style of accessing the point, yet keeping the x/y/z style so that he doesn't have to change his code. – Rafid Dec 24 '10 at 19:54
  • 2
    If you're going to assert x <= 2, it'd be nice to also add 0 <= x. – Fred Nurk Dec 25 '10 at 00:59
12

OK, this should work for you

struct {
    union {
        float coord[3];
        struct
        {
            float x,y,z;
        };
    };
} Vertex;

What this code does is that it unions the array with the structure, so they share the same memory. Since the structure doesn't contain a name, it is accessible without a name, just like the union itself.

Rafid
  • 18,991
  • 23
  • 72
  • 108
  • 1
    ;-) OK, don't worry, I gave you "up" for your comment :-) – Rafid Dec 24 '10 at 19:15
  • 8
    Unfortunately, it's not standard C++. – Yakov Galka Dec 24 '10 at 19:23
  • Hmmm... didn't know this before! You mean it won't be accepted in GCC for example? I am sure I have made it in VC++, but Microsoft has never been bound to the specs :-) – Rafid Dec 24 '10 at 19:27
  • 5
    It technically violates the union storage rules. You are only allowed to read from the element of the union to which you last wrote. So, if you write to `coord[1]`, you can only read from the `coord` array and cannot read from `x`, `y`, or `z`, and if you write to `z`, you can only read from the `x`, `y`, and `z` elements but not from the `coord` array. There could also be padding between the elements of the struct (that is highly unlikely, but it's possible). Saying it's not valid C++ is a pedantic, but valid, complaint. – James McNellis Dec 24 '10 at 19:30
  • Why is it not standard? Is it because the anonymous struct? – Artium Dec 24 '10 at 19:30
  • 3
    AFAIK VC++ says "non-standard extension used" and in GCC you can turn-on this feature by some flag. Yet, C99/C++98,03,0x standards have only anonymous unions, not anonymous structs. – Yakov Galka Dec 24 '10 at 19:30
  • @ybungalobill: Oh, yes; you're referring to the declaration itself not being valid. That's also true. – James McNellis Dec 24 '10 at 19:33
  • 2
    @All: related: http://stackoverflow.com/questions/1972003/how-to-use-anonymous-structs-unions-in-c and http://stackoverflow.com/questions/2253878/why-does-c-disallow-unnamed-structs-and-unions – Yakov Galka Dec 24 '10 at 19:36
  • 1
    Very interesting! One thing I always believed in: No matter how long you work in C++, you will always discover new things! – Rafid Dec 24 '10 at 19:53
  • @R.: apparently you're right, it doesn't. Sorry, I'm not a C programmer :) – Yakov Galka Dec 25 '10 at 11:11