3

This might be an odd question, but how does one nicely loop over ALL values of a type. In particular the standard integral types such as unsigned short. A normal for loop construct presents a difficulty: what condition to use to exit the loop - because all values are valid.

Of course, there are several ways to get the job done. Exit on the last value then handle that after the loop. Use a bigger int to count. The question is, is there a more elegant way?

wxffles
  • 864
  • 6
  • 20
  • Sounds like you're trying to brute-force something? Don't try this with a 64-bit integer though... – Mysticial Jan 31 '12 at 23:12
  • [Iterating over all unsigned integers in a for loop](https://stackoverflow.com/q/40432995/995714) – phuclv Aug 03 '18 at 02:15

7 Answers7

4
#include <limits>
int i = std::numeric_limits<int>::min();
do {
    ...
    if(i == std::numeric_limits<int>::max())
        break;
    i++;
} while(true);

This is in contrast to a for() statement which translates to:

#include <limits>
int i = std::numeric_limits<int>::min();
while(true) {
    if(i == std::numeric_limits<int>::max())
        break;
    ...
    i++;
};
Aleksandr Dubinsky
  • 22,436
  • 15
  • 82
  • 99
4

I worried about this very same issue once, and this is the best I could think of:

unsigned char c = 0;
do
{
    printf("%d ", (int)c); //or whatever
} while (++c != 0);

One of the very few cases where I find the do..while syntax useful.

Note that technically it is only valid for unsigned types, as I am relying on the wrapping of values.

rodrigo
  • 94,151
  • 12
  • 143
  • 190
4

If you want a pretty solution you can do this:

for(auto x : everyvalue<short>()) {
  std::cout << x << '\n';
}

Where everyvalue is:

#include <limits>
template<typename T>
struct everyvalue {
  struct iter {
    T x;
    bool flag;
    inline iter operator++() {
      if(x == std::numeric_limits<T>::max())
        flag = true;
      else
        ++x;
      return *this;
    }
    inline T operator*() { return x;}
    inline bool operator!=(iter& i) {return flag != i.flag;}
    // note: missing some iterator requirements, still should work
  };
  inline iter begin() { return iter{std::numeric_limits<T>::min(),0}; }
  inline iter end() { return iter{std::numeric_limits<T>::max(),1}; }
};

Otherwise a simple break would be preferred.

Pubby
  • 51,882
  • 13
  • 139
  • 180
  • 1
    I'm going to give this answer the big green tick. The end result is elegant and generalised. All the ugly stuff is done once, done right and hidden away, which is a big part of how C++ should be used (in my opinion). Some of the other answers may have performance advantages, but that wasn't what I was after. – wxffles Feb 01 '12 at 20:46
1

You can combine the value by which you increment with a flag to say you've reached the max so you don't increment past it:

for ( char i ( std::numeric_limits<char>::min() ), j ( 1 );
      i != std::numeric_limits<char>::max() || j--;
      i += j )
    std::cout << ( int ) i << '\n';

but only elegant as in 'sophisticated' rather than 'clean simple lines'.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
0

Look up the minimum and maximum values?

Stu
  • 15,675
  • 4
  • 43
  • 74
  • I suggest you read the question again. This has the same problem as the other (now-deleted) answer. – flight Jan 31 '12 at 23:15
0

You can just use a larger type:

unsigned long i;
for (i = std::numeric_limits<unsigned short>::min();
     i <= std::numeric_limits<unsigned short>::max();
     i++)
Carl Norum
  • 219,201
  • 40
  • 422
  • 469
  • `i <= i != [...]`? Was that just meant to be `i <= [...]`? – flight Jan 31 '12 at 23:16
  • 1
    +1 Of course, assuming `unsigned long` really is larger than `unsigned short`. It is on implementations I know of, but I'm just pointing it's not guaranteed. – R. Martinho Fernandes Jan 31 '12 at 23:17
  • True. A check for appropriate type sizes would be a good idea. – Carl Norum Jan 31 '12 at 23:18
  • This was one of the solutions I already suggested, but my issue with this approach is that you then have to cast i down to an unsigned short before you can use it. Or you could maintain an additional variable of the right type. – wxffles Jan 31 '12 at 23:27
  • 1
    @wxffles the cast is safe because you know for a fact that the value fits in the smaller type. – R. Martinho Fernandes Jan 31 '12 at 23:29
0

I recently asked the same question about bools: How to write a `for` loop over bool values (false and true). You may look for the answers there. I then realized that since a for-loop iterating over all possible values would need to evaluate the condition one more time, you need an extra value (in any form - a bigger type, a second variable, etc) to properly distinguish all cases. And, a do-while loop works for this case because it needs exactly as many comparisons as there are distinct values.

Community
  • 1
  • 1
Alexey Kukanov
  • 12,479
  • 2
  • 36
  • 55