-4

I need a struct that can hold 3 coordinates as separate variables, but I also need a way to iterate through them. For now, I am doing it like this:

struct Vector3
{
    float coords[3];
    float& x = coords[0];
    float& y = coords[1];
    float& z = coords[2];
};

This way I can access each individual variable as well as iterate through all of them using the coords array. Problem is: this is very unefficient, both in memory usage and in performance cost. Is there a better solution?

2 Answers2

2

As suggest (by underscore_d) in a comment the preferred way is to provide accessor functions. On any realistic compiler they'll be optimised away so no space or performance issue.

struct Vector3 {
    float coords[3];
    float& x() { return coords[0]; }
    float& y() { return coords[1]; }
    float& z() { return coords[2]; }
    
    float x() const { return coords[0]; } 
    float y() const { return coords[1]; }
    float z() const { return coords[2]; }
    
};

Here's a little program that gives it a run out.

#include <iostream>

struct Vector3 {
    float coords[3];
    float& x() { return coords[0]; }
    float& y() { return coords[1]; }
    float& z() { return coords[2]; }
    
    float x() const { return coords[0]; } 
    float y() const { return coords[1]; }
    float z() const { return coords[2]; }
    
};

void dump(const std::string& title,const Vector3& v3){
    std::cout << title << '\n';
    std::cout << "{ " << v3.coords[0] << " , " << v3.coords[1] << " , " << v3.coords[2] << " }\n";
    std::cout << "x=" << v3.x() << " y=" << v3.y() << " z=" << v3.z() << '\n' << std::endl;
}

int main() {
    Vector3 v3{};
    
    dump("v3 0:",v3);
    
    v3.x()=7.0f;
    v3.y()=3.141f;
    v3.z()=276.0f;
    
    dump("v3 1:", v3);
    
    Vector3 v3c{};
    
    dump("v3 c 0:", v3c);
    v3c=v3;
    dump("v3 c 1:",v3c);
    
    return 0;
}

Don't overlook that the assignment v3c=v3 now works 'out of the box'. Bonus! The references broke the default assignment operator. References can't be assigned to be references to other things (in this case the coordinate in the other object - as C++ sees it).

I've provided two sets of getters - const and non-const - you may not be managing const-ness.

You mention iteration. If you this to the structure definition:

const float * begin() const { return coords;}
const float * end() const { return coords + 3; /* Yes 3 */}
float * begin() { return coords;}
float * end() { return coords + 3; /* Yes 3 */}

You can use C++ ranged-for loops : for(auto curr : vec ) as well. This snippet sets all the coords of v3 to 7.0.

for(auto& curr : v3){
    curr=7.0f;
}

I also recommend adding a constructor: Vector3():coords{} {} to the struct to initialise all the coordinates to zero. It has a tiny overhead but experience shows its usually the best to avoid 'weird' bugs down the line.

The modern recommendation is to prefer double over float unless you have good reason. I at least recommend creating a master typedef float float_type; and using that consistently in your code. It won't save you any re-engineering but it will reduce the rework if you change take. Also observe "almost always auto". constexpr float_type zero{0}; may also help.

Expected program output:

v3 0:
{ 0 , 0 , 0 }
x=0 y=0 z=0

v3 1:
{ 7 , 3.141 , 276 }
x=7 y=3.141 z=276

v3 c 0:
{ 0 , 0 , 0 }
x=0 y=0 z=0

v3 c 1:
{ 7 , 3.141 , 276 }
Persixty
  • 8,165
  • 2
  • 13
  • 35
1

Iterate through variables in a struct c++

There is no standard way to do this.

You could for example implement a custom iterator to do this. However, for random access, an array is likely to produce efficient code.

This way I can access each individual variable as well as iterate through all of them using the coords array. Problem is: this is very unefficient

You don't need the references to access individual elements. This works just fine:

struct Vector3
{
    float coords[3];
} v;

v.coords[0] = 42; // access first element
eerorika
  • 232,697
  • 12
  • 197
  • 326