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 }