Spock
Spock

Reputation: 67

How to condense multiple for loops with different initial values

In a function, I have several consecutive for loops with the same code but different initial values for the control variable. The initial values are obtained from inputs to the function. Ie,

void thisFunction( class A a){
  //some other code

  for (int i = a.x; i != 0; --i){
    code
  }

  for (int i = a.y; i != 0; --i){
    code
  }

  for (int i = a.z; i != 0; --i){
    code
  }

  //some other code
}

Is there any way to condense all the for loops into one loop so that when I make changes to the code within the loop, I won't have to change it for all three loops? An alternative is to write anotherFunction() with the initial values as input, but I need access to local variables in thisFunction().

  void anotherFunction(int in){
      for (int i = in; i != 0; --i){
        code
      }
  }

So is there another way to condense the loops?

Thank you.

Upvotes: 4

Views: 919

Answers (5)

Grim Fandango
Grim Fandango

Reputation: 2426

You can use macro

#define ITERATE(_IN)   \
{\
      for (int _I = (_IN); _I != 0; --_I){\
         code       \
      }\
}\

Then you have access to local variables, and you only have to manage one copy of the code. So, your code becomes

void thisFunction( class A a){
  //some other code

  ITERATE(a.x)
  ITERATE(a.y)
  ITERATE(a.z)

  //some other code
}

This may become difficult to debug, so you have to make sure first that it works well, before you make a macro of your code

Upvotes: 1

EDIT: In most cases you should avoid doing this, and rather follow MSalter's answer. Just because you can, doesn't mean you should.

I am not sure how good an idea this is, but without any more context, a simple solution could be:

int starts[3] = { a.x, a.y, a.z };
for ( int var = 0; var < 3; ++var ) {
   for ( int i = starts[var]; i != 0; --i ) {
      // code
   }
}

Note that the values of the conditions are obtained once at the beginning of the function, that means that if the object a changes throughout the first loop, that change will not be visible in the later control loops. If you need that, the solution can be modified to store pointers.

EDIT: There is a comment suggesting the use of the size of the array. I did not add that here not to modify, but anyway, a better way of getting the array size is:

template<typename T, unsigned int N>
inline unsigned int array_size( T (&)[N] ) {
   return N;
}
//...
for ( int var = 0; var < array_size(starts); ++i ) {

Upvotes: 7

Henrik
Henrik

Reputation: 23324

Using lambda expressions, you could do this:

void thisFunction( class A a)
{ 
    //some other code 
    auto code = [&] (int i)  
    { 
        // your code here 
    }; 

    for (int i = a.x; i != 0; --i)   
        code(i); 
    for (int i = a.y; i != 0; --i)   
        code(i); 
    for (int i = a.z; i != 0; --i)   
        code(i); 
}

Upvotes: 2

MSalters
MSalters

Reputation: 179799

Your hunch is right - you'll have to refactor your code into a separate function. Local variables of thisFunction will become arguments to anotherFunction; often these will be passed by reference .

Upvotes: 9

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272487

Not really. The loops will all be running for different numbers of iterations, surely?

The best you can do is factor out as much of the internals as possible, for instance, into a function like you suggested. Alternatively, have the loop outside the function.

To avoid passing in a load of variables independently, you could consider wrapping them in a class or struct.

Update On second thoughts, David Rodriguez's answer suggestion is a pretty good solution!

Upvotes: 0

Related Questions