Sunius
Sunius

Reputation: 2907

Prettiest way to iterate all values of an unsigned integer

I want to iterate all possible values of an integer. This code does not work as the termination condition never becomes false:

for (uint32_t i = 0; i <= 0xFFFFFFFF; i++)
    std::cout << i << std::endl;

I've come up with this:

auto loopBody = [](uint32_t value)
{
    std::cout << value << std::endl;
};

uint32_t last = 0xFFFFFFFF;
for (uint32_t i = 0; i < last; i++)
    loopBody(i);

loopBody(last);

It is fairly ugly, though. Is there a prettier way to do this?

Upvotes: 5

Views: 2888

Answers (4)

Nikos C.
Nikos C.

Reputation: 51930

You cannot check for the break condition in the loop header, since for that you would need to exclude the maximum value.

Instead, do the check in the loop body and leave the check in the header empty:

for (auto i = std::numeric_limits<int>::lowest(); ; ++i) {
    std::cout << i << '\n';
    if (i == std::numeric_limits<int>::max())
        break;
}

With a do-while loop, you don't need to check inside the loop body, but you need to move the counter variable to the outer scope, and if you want to avoid undefined behavior, you can only use unsigned integer types:

auto i = std::numeric_limits<unsigned>::lowest();
do {
    std::cout << i << '\n';
} while (i++ < std::numeric_limits<unsigned>::max());

Note that the i++ will overflow, but that only happens after acquiring the current value (we're using postfix increment.) With signed integers however, this overflow would be undefined behavior, and even though we're not using the value after the overflow occurs, undefined behavior can have unpredictable results, even before it actually occurred.

Upvotes: 1

HolyBlackCat
HolyBlackCat

Reputation: 96959

I would use something like this:

uint32_t i = 0;
do
{
    // Your code here.
    i++;
}
while (i != 0);

I personally find it more elegant than a solution involving std::numeric_limits.


As @NicosC said, keep in mind that you should not do same trick with signed integers, because signed overflow is undefined behavior.

Upvotes: 5

Severin Pappadeux
Severin Pappadeux

Reputation: 20130

Well, it call for condition test at the end of the loop, which means using do {} while()

#include <limits>
#include <iostream>

int main() {
    auto beg = std::numeric_limits<unsigned>::lowest();
    auto end = std::numeric_limits<unsigned>::max();

    std::cout << beg << " " << end << std::endl;

    long long count = 0LL;

    auto i = beg;
    do {
        ++count;
        if ((count % (1024LL*1024LL)) == 0)
            std::cout << count << std::endl;
    } while(i++ != end);
    std::cout << count << std::endl;

    return 0;
}

Upvotes: 1

Maikel
Maikel

Reputation: 1269

I would use std::numeric_limits as it states your intent best.

int lowest = std::numeric_limits<int>::lowest();
int max    = std::numeric_limits<int>::max();
for (int i = lowest; i < max; ++i)
   cout << i << '\n';
cout << max << '\n';

or in a function see this Demo

#include <iostream>
#include <limits>
#include <functional>

template <class T>
void for_all(std::function<void(T)> fn)
{
    T lowest = std::numeric_limits<T>::lowest();
    T max    = std::numeric_limits<T>::max();
    for (T i{lowest}; i < max; ++i)
       fn(i);
    fn(max);
}

int main()
{
    for_all<int>([](int i) { 
        std::cout << i << std::endl;
    });
}

Edit: I edited the comparison

Edit 2: See comments. Props to kec ;-)

Upvotes: 0

Related Questions