C ++ Index Class Members
I have a class vector
class vector3f
{
public:
float x;
float y;
float z;
};
If I want to access one of the members, I need to enter vec.x, vec.y and vec.z. Now I have an algorithm that is supposed to access data members per index, for example:
for(int i = 0; i < 3; i++)
{
vec[i] = i*i;
}
Doing this without an index will result in multiple if-conditions:
for(int i = 0; i < 3; i++)
{
if(i == 0){vec.x = i*i;}
else if(i == 1){vec.y = i*i;}
else if(i == 2){vec.z = i*i;}
}
Is there a way to index data items so that they are resolved at compile time? I don't want to use an array in a vector class because accessing data members with vec.x, vec.y and vec.z is more programmer friendly. What would be the best solution to avoid these if-conditions?
source to share
You can overload operator[]
for your class to localize those conditions if
(or preferably a switch
) in one place:
class vector3f
{
public:
float x;
float y;
float z;
float& operator[] (size_t i)
{
switch (i) {
case 0: return x;
case 1: return y;
case 2: return z;
default: throw "something";
}
}
float operator[] (size_t i) const
{ return (*const_cast<vector3f*>(this))[i];
}
This is a common and safe way to do this.
If your class is in fact a standard layout class 1 as you showed, and if you know the alignment and padding scheme of your compiler / platform, and if you know from them what float
will just sit back and forth in memory, you can also implement this operator:
float& operator[] (size_t i)
{
return (&x)[i];
}
This refers to x
how the beginning of the float
s array . It will be faster, but relies on the ifs I mentioned above and does not do bounds checking.
1 Which basically means it has no non-empty base classes, no features, virtual
and no data item of type custom layout.
source to share
Not really at compile time, but you can optimize.
You can use a pointer-member variable and then an array of it. Start with:
float vector3f::*px;
px = &vector3f::x;
(vec.*px) = 10.2;
Then you declare an array of pointer to element:
float vector3f::*pArray[3];
Assign them:
pArray[0] = &vector3f::x;
pArray[1] = &vector3f::y;
pArray[2] = &vector3f::z;
Use them:
(vec.*pArray[0]) = 10.2; // This is vector3f::x
(vec.*pArray[1]) = 1042.5; // This is vector3f::y
And change the loop body accordingly to index the corresponding element pointer!
source to share
An interesting alternative can be obtained using references .
class vector3f
{
public:
float &x, &y, &z;
float value[3];
vector3f() :
x(value[0]), y(value[1]), z(value[2]){}
};
Here we bind x to value [0], y to value [1], and z to value [2] - these are aliases for array entries, but note that they allocate an extra 4 bytes per class reference. This way we can name our array for ease of user access.
We can also avoid calling the overloaded runtime operator [
(but a good compiler should have built-in access, switch / case access anyway).
Usage example:
vector3f test;
test.value[0] = 227.f;
test.value[1] = 42.f;
test.value[2] = -1.f;
printf("Values are %lf, %lf and %lf.",test.x,test.y,test.z);
Resulting output:
Values are 227.000000, 42.000000 and -1.000000.
source to share