1

I'd like to know if it is actually possible to create / define an homemade for statement in C++. Something similar already have been asked here:

"How to create a for loop like command in C++? #user9282's answer"

What I ask for is if we can make a for that performs as much for as we want (n times).

As example, here is a basic for-loop statement :

for (int i = 0; i < 10; i++) { ... }

I'm wondering if the new for-loop could result more like this :

int x = 20; // individual loops
int y = 3; // = amount of for-loops performed (in this case, 3)

// maybe some code generating for-loops here or something...

// result:
for (int i = 0; i < x; i++)
{
    for (int j = 0; j < x; j++)
    {
        for (int k = 0; k < x; k++)
        {
            // if "y" was equal to 5, there would be 2 more for-loops here
            instructions; // we can use "i", "j", "k", ... here
        }
    }
}

Do you think this could be possible in c++ ?

[EDIT: made clearer the code above]

In one sentence: I want to create a statement (e.g. if, while, for, switch) that puts for-loops into for-loops (just like the code above has for-loops into for-loops) so we can access multiple increments (i, j, k, ...) in the same scope.

Community
  • 1
  • 1
whiteiden97
  • 33
  • 1
  • 7

4 Answers4

5

You can easily do that with recursive functions that contains a for loop. I would do it like this:

void foo() {
    for (...) {
        foo();
    }
}

That way, you can do as many nested for loops as you want.

However, if you want define a recursive nested for loops in your code without defining an external function, you could use lambdas:

auto recursive = [](auto func) {
    // This is needed to make a recursive lambda
    return [=](auto... args){
        func(func, args...);
    };
};

auto nestedForLoop = recursive([](auto self){
    // Here's your recursive loop!
    for (...) {
        self();
    }
});

// You can simply call `nestedForLoop` to execute loop
nestedForLoop();
Guillaume Racicot
  • 39,621
  • 9
  • 77
  • 141
4

If you have n nested for loops with the same bound x, you are performing xn iterations. In that case, you can just use a single index and convert it into multiple indices for convenience. For n = 2, for example:

for (int z = 0; z < x * x; ++z) {
  const int i = z / x;
  const int j = z % x;
  // ...
}

For n = 3:

for (int z = 0; z < x * x * x; ++z) {
  // The last "% x" in this line is for illustration only.
  const int i = (z / x / x) % x;
  const int j = (z / x) % x;
  const int k = z % x;
  // ...
}

i, j, k, etc. are the digits of the current iteration number z converted to base x. You could generalise this into a recursive function, or one that unpacks the digits into a vector.

Jon Purdy
  • 53,300
  • 8
  • 96
  • 166
  • 1
    your answer nicely and easily solves my problem... it's so simple when you think about it! Thanks man! – whiteiden97 Feb 06 '17 at 05:20
  • 2
    For performance reasons it may be better to have one instance of y elements containing the particular counters, and increment them (with overflow logic) instead of single `z` splitting by div/modulo (also this will probably overflow `int` quite fast, consider `x = 16, y = 8` will already overflow 32b `int`, while incrementing elements `std::array` from 0 to 15 will still work. – Ped7g Feb 06 '17 at 12:15
  • `1.7*10^308` is the highest value doubles can handle, beside to `2^32` for integers. We could then use a double as counter instead of using an integer. We will probably loose performences doing this, but still the counter will be much bigger. – whiteiden97 Feb 06 '17 at 13:42
  • @Ped7g: Yes, it would be more efficient to update the counters incrementally rather than recalculating with division. I wanted to present the general formula first. – Jon Purdy Feb 06 '17 at 21:11
  • @whiteiden97: A 64-bit integer would be preferable. Remember that floating-point numbers have higher range but lower precision—as your numbers get larger, there are fewer representable values, so you can only represent integers in the range of the mantissa, [-2^54,+2^54] for an IEEE754 `double`. This is still quite large, but there’s no reason to involve floating-point. – Jon Purdy Feb 06 '17 at 21:16
  • @whiteiden97 no, that's not how doubles work. 1.7^e308 looks large, but actually it's still only 64 bits of information, so technically if you would use that double for the div/modulo sequence with let's say 10 bit large dividend, somewhere around 7th sub-counter you would start to receive all zeroes for the remaining modulus. Also doing +1 would have no effect, so you would get infinite loop. (I mean 1e40 + 1 is again the same 1e40, nothing will change, due to low precision of native FP numbers) – Ped7g Feb 06 '17 at 22:09
  • Thanks for answers! I was knowing doubles were loosing precision when becoming too small, but didn't know that it was still the case when going too large! 64 integers (or longs) are then going to be a mutch better choice. – whiteiden97 Feb 07 '17 at 17:26
  • @whiteiden97 that's again not accurate. The FP HW-native numbers have sort of "fixed" precision, about 6 to 9 most significant digits can be encoded precisely into float (32b), double can hold about 15-17 most significant digits. So very small numbers around zero are actually encoded with full possible precision, but for example `double(1e30 + 1e-30)` will end with unmodified `double(1e30)`, because the fraction is way too far from the 15-17 digits precision. While `1e-30 + 1e-35` will work nicely as cca. `1.00001e-30`, as both fractions fits into the most significant digits part. – Ped7g Feb 08 '17 at 14:26
-1

Quick answer:

#include <iostream>

using namespace std;

void recursive(int x, int y, int tempY) // 2d recursive for loop 
{
    if (x > 0)
    {
        if (y > 0)
        {
            cout << x << " " << y << " \n ";
            recursive(x, y - 1, tempY);
        }
        else
        {
            y = tempY;
            recursive(x - 1, y, tempY);
        }
    }
}

void recursive(int x, int y, int z, int tempY, int tempZ) // 3d recursive for loop
{
    if (x > 0)
    {
        if (y > 0)
        {
            if (z > 0)
            {
                cout << x << " " << y << " " << z << " \n ";
                recursive(x, y, z - 1, tempY, tempZ);
            }
            else
            {
                z = tempZ;
                recursive(x, y - 1, z, tempY, tempZ);
            }
        }
        else
        {
            y = tempY;
            recursive(x - 1, y, z, tempY, tempZ);
        }
    }
}

int main()
{ 
    recursive(1, 2, 2); // x = 1, y = 2
    recursive(1, 2, 3, 2, 3); // x = 1, y = 2, z = 3
}
myworldbox
  • 361
  • 6
  • 11
-1

Quick answer:

void n_for_loop(int x, int size, int arr[])
{
    static int* arrTemp(new int[size]);
    if (x >= size)
    {
        for (int i = 0; i < size; i++)
        {
            cout << arrTemp[i] << " ";
        }
        cout << endl;
        return;
    }
    for (int i = 0; i < arr[x]; i++)
    {
        arrTemp[x] = i;
        n_for_loop(x + 1, size, arr);
    }
}
myworldbox
  • 361
  • 6
  • 11