Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Index class members

Tags:

c++

I have a class vector

class vector3f
{
public:
float x;
float y;
float z;
};

If I want to access one of the members I have to type vec.x, vec.y and vec.z. Now, I have an algorithm that should access the data members per index, for example:

for(int i = 0; i < 3; i++)
{
vec[i] = i*i;
}

Doing this without an index would result in several 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 the data members so that they are resolved in compile-time? I don't want to use an array in the vector class because accessing the data members with vec.x, vec.y and vec.z is more convenient for the programmer. What would be the best solution to avoid these if-conditions?

like image 848
user3067395 Avatar asked Oct 31 '14 08:10

user3067395


2 Answers

You can overload operator[] for your class to localise those if conditions (or preferably a switch) into 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];
}

That's the generic and safe way of implementing this.

If your class is actually a standard-layout class1, as you have shown, and if you know the alignment and padding scheme of your compiler/platform, and if you know from these that the floats will just be arranged after each other in memory, you can implement the operator like this as well:

float& operator[] (size_t i)
{
  return (&x)[i];
}

This treats x as the start of an array of floats. It will be faster, but relies on the ifs I mentioned above, and does not do bounds checking.


1 Which basically means it doesn't have non-empty base classes, doesn't have virtual functions and doesn't have a data member of non-standard-layout type.

like image 73
Angew is no longer proud of SO Avatar answered Nov 09 '22 06:11

Angew is no longer proud of SO


Not absolutely at compile time, but you can optimize.

You can use pointer-to-member-variable, and then its array. Start with:

float vector3f::*px;
px = &vector3f::x;
(vec.*px) = 10.2;

You then declare array of pointer-to-member:

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 appropriately change the loop body to index appropriate pointer-to-member!

like image 30
Ajay Avatar answered Nov 09 '22 07:11

Ajay