0

I have a vector class

class vec3
{
public:
    FLOAT x, y, z;

    vec3(FLOAT X = 0, FLOAT Y = 0, FLOAT Z = 0)
    {
        x = X;
        y = Y;
        z = Z;
    }
};

And I need to be able to use this vector as either spacial dimension using x, y, z, or as color using r, g, b or as measure dimensions using w, h, l.

It would be a waste of memory to have this vector class containing 9 members. Instead I want it to contain x, y and z and refer to them as stated above.

I already searched online and found almost fitting solutions, see C++ member variable aliases?

But the thing is, if I use something like

struct Vertex {
    float& r() { return values[0]; }
    float& g() { return values[1]; }
    float& b() { return values[2]; }

    float& x() { return values[0]; }
    float& y() { return values[1]; }
    float& z() { return values[2]; }

    float  operator [] (unsigned i) const { return this->values_[i]; }
    float& operator [] (unsigned i)       { return this->values_[i]; }
    operator float*() const { return this->values_; }

private:
    float[3] values_;
}

then I can only read the struct members, not set them, and if I use

struct vertex
{
private:
    float data[3];
public:
    float &x, &y, &z;
    float &r, &g, &b;

    vertex() : x(data[0]), y(data[1]), z(data[2]), r(data[0]), g(data[1]), b(data[2]) {
    }

    float& operator [](int i) { 
        return data[i];
    }
};

then the struct increases in memory because each reference takes up space.

1 Answers1

1

Actually your solution should work since you're returning by reference. The only caveat is you have to use () on each access.

class vec3
{
    FLOAT _x, _y, _z;

public:
    inline FLOAT &r() { return _x; }
    inline FLOAT &g() { return _y; }
    inline FLOAT &b() { return _z; }

    inline FLOAT &x() { return _x; }
    inline FLOAT &y() { return _y; }
    inline FLOAT &z() { return _z; }


    vec3(FLOAT X = 0, FLOAT Y = 0, FLOAT Z = 0)
    {
        _x = X;
        _y = Y;
        _z = Z;
    }
};


int main(int argc, char **argv)
{
    vec3 myVec(1, 2, 3);

    printf("r = %f, g = %f, b = %f\n", myVec.r(), myVec.g(), myVec.b());
    myVec.x() = 10;
    printf("r = %f, g = %f, b = %f\n", myVec.r(), myVec.g(), myVec.b());
    return 0;
}

Output:

r = 1.000000, g = 2.000000, b = 3.000000
r = 10.000000, g = 2.000000, b = 3.000000
Jon Reeves
  • 2,426
  • 3
  • 14
  • I see, so is it not possible to have a struct / class that has member aliases that 1. Don't take up additional memory and 2. Don't need a ```()``` every time I call them? – Kittenpaw Fromsoftfur May 04 '21 at 18:15
  • @KittenpawFromsoftfur The accessor methods don't take up additional memory. In fact, you can take `sizeof(vec3)` and `printf` the result, and you'll get 12, the size of 3 floats. The additional methods will be optimized out entirely by the compiler. Try it yourself! As for getting rid of the `()`, I don't have a solution for you, but I can tell you that having them there is idiomatic, and very common in C++ development. – Jon Reeves May 04 '21 at 18:25
  • @KittenpawFromsoftfur I guess you could create temporary accessor views over the object to get access to `r`, `g`, `b` etc. depending on the situation. These objects would most probably be optimized out and take no space. [Example](https://godbolt.org/z/EE3fEW86r). I'd probably create a base class and inherit that and add accessor methods instead. Less risky. – Ted Lyngmo May 04 '21 at 18:43