Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ access multiple members by array

Tags:

c++

Lot's of year from last project in C++, I cannot remember/find how to do this.

Sample (pseudo code) :

    MyClass
    {
    public :
        float x;
        float y;
        float z;
    }

    main.cpp

    void MyFunction(void)
    {
        MyClass *myclass = new MyClass(); 
        float x = myclass->x;

        //want I want :
        float *xyz = myclass->xyz;
    }

How to do this ?

Thank you very much and sorry for my poor english.

[EDITED] It's only a concept now, but the goal, is near the vec4 class in GLSL (OpenGL Shader for GPU). Vec4 is a math vector class with four values (x, y, z, w). You can get/assign value like this sample :

vec4 vectorA = vec4(1.0, 1.0, 1.0, 1.0);
vectorA.x = 2.0;
vec2 vectorB = vectorA.xy;
vec3 vectorC = vectorA.xxx;

etc. (so : VectorC.x = 2.0, vectorC.y = 2.0, vectorC.z = 2.0)

like image 501
chrisendymion Avatar asked Mar 19 '26 13:03

chrisendymion


1 Answers

Use unnamed structure:

union Vector
{
    struct 
    {
        float x;
        float y;
        float z;
    };
    float xyz[3];
};

Then you can access components without implicitly referencing containing structure:

int main()
{ 
    Vector* vec = new Vector();
    vec->x = 50;
    vec->y = 30;
    vec->xyz[2] = vec->xyz[0] + vec->xyz[1]; // vec->z == 80
    delete vec;
    return 0;
}

Of course, you can wrap this union with another structure/class, to same effect:

class MyClass
{
public:
    union
    {
        struct 
        {
            float x;
            float y;
            float z;
        };
        float xyz[3];
    };
};

Also, why create your structure on heap (using "new")? Won't allocating on stack do?

EDIT: Oh, I get it. Well, it's definitely doable, but it is worth it only if you want as much compability with GLSL as possible. The idea is to create a "proxy" that stores references for each component variation. The tradeof is that vec2, instead of taking 8 bytes of memory will take 40 bytes. It will obviously get much, much worse for vec3 & vec4

class vec2
{
    // private proxy, auto-convertible into vec2
    struct proxy2
    {
        // store references, not values!
        proxy2(float &x, float &y) : x(x), y(y) {}
        // implicit conversion to vec2
        operator vec2() { return vec2(x, y); }
        // support assignments from vec2
        proxy2& operator=(const vec2& vec) 
        { 
            x = vec.x; 
            y = vec.y; 
            return *this; 
        }
    private:
        // hide copy and assignment operators
        proxy2(const proxy2&);
        proxy2& operator=(const proxy2&);
        // hide member variables
        float& x;
        float& y;
    };

public:
    vec2(float _x, float _y) 
        : x(_x), y(_y) 
        , xx(x, x), xy(x, y), yx(y, x), yy(y, y)
    {}

    vec2(const vec2& vec)
        : x(vec.x), y(vec.y)
        , xx(x, x), xy(x, y), yx(y, x) , yy(y, y)
    {}

    float x;
    float y;
    proxy2 xx;
    proxy2 xy;
    proxy2 yx;
    proxy2 yy;
};

With this class you can get syntax pretty close to what GLSL offers:

vec2 v(1.0f, 2.0f);
vec2 vxx = v.xx; // 1, 1
vec2 vyx = v.yx; // 2, 1
vec2 vxy = v.xy; // 1, 2
vec2 vyy = v.yy; // 2, 2

v.yx = vec2(3, 4); // 4, 3
v.y = 5;           // 4, 5

vec2::proxy2 proxy = v.xx;     // compile error
v.xx = vec2::proxy2(v.x, v.y); // compile error

To extend this to support vec3 and vec4 simply derive from vec2 and vec3 respectively, create proxy3 and proxy4 structs and declare member for each component variation (27 for vec3 and mere 64 for vec4).

EDIT2: New version, that does not take extra space at all. Again, unions to the rescue! Converting proxy2 to a template and adding data member that matches vec2 components you can safely put it into an union.

class vec2
{
    // private proxy, auto-convertible into vec2
    template <int x, int y>
    struct proxy2
    {
        // implicit conversion to vec2
        operator vec2()
        { 
            return vec2(arr[x], arr[y]); 
        }
        // support assignments from vec2
        proxy2& operator=(const vec2& vec) 
        { 
            arr[x] = vec.x; 
            arr[y] = vec.y; 
            return *this; 
        }
    private:
        float arr[2];
    };

public:
    vec2(float _x, float _y) 
        : x(_x), y(_y) 
    {}

    vec2(const vec2& vec)
        : x(vec.x), y(vec.y)
    {}

    union
    {
        struct 
        {
            float x;
            float y;
        };
        proxy2<0, 0> xx;
        proxy2<0, 1> xy;
        proxy2<1, 0> yx;
        proxy2<1, 1> yy;
    };
};

Hope this is what you are after.

EDIT3: I took me a while, but I came up with a working GLSL emulation library (includes swizzling) allowing you to run fragment shaders without modifications. If you are still interested, you should take a look.

like image 106
gwiazdorrr Avatar answered Mar 21 '26 02:03

gwiazdorrr



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!