44

I get warning signed/unsigned mismatch for the following code:

auto n = a.size();
for (auto i = 0; i < n; i++) {
}

The problem is that by assigning 0 to i it becomes int rather than size_t. So what is better:

size_t n = a.size();
for (size_t i = 0; i < n; i++) {
}

or this:

auto n = a.size();
for (size_t i = 0; i < n; i++) {
}

or maybe you have a better solution? I like the first one more because it is bit more consistent, it just uses size_t rather than both size_t and auto for the same purpose.

Jason Sundram
  • 12,225
  • 19
  • 71
  • 86
user2381422
  • 5,645
  • 14
  • 42
  • 56
  • 3
    how about `auto i = 0u`? – jalf Jul 08 '13 at 08:57
  • 1
    How about using an int if you need an index in your loop? Using an unsigned index can get nasty very quickly. E.g. `i < n - 1` is wrong when `i` and `n` are unsigned. – D Drmmr Apr 19 '14 at 18:27

9 Answers9

57

A range based loop could be a cleaner solution:

for (const auto& i : a)
{

}

Here, i is a const reference to an element of container a.

Otherwise, if you need the index, or if you don't want to loop over the entire range, you can get the type with decltype(a.size()).

for (decltype(a.size()) i = 0; i < a.size(); ++i) {
}
juanchopanza
  • 223,364
  • 34
  • 402
  • 480
  • 8
    1 problem with range based loop is that index isn't available – RiaD Jul 06 '13 at 17:15
  • Yeah that is big problem actually, I don't want to manage the indexes separately. – user2381422 Jul 06 '13 at 17:16
  • Thank you for this. I didn't know C++11 introduced range based loop. – stepanbujnak Jul 06 '13 at 17:18
  • @user2381422 Right, one possible advantage of the `decltype` version is that you have the index, if you need it. I edited the answer to make this clear. – juanchopanza Jul 06 '13 at 17:20
  • 5
    `decltype(n) i = 0` would be shorter and clearer, wouldn't it? –  Jul 06 '13 at 17:22
  • @delnan yes, correct. I hadn't even noticed the `n` in my answer. It was meant to be `n`-less. – juanchopanza Jul 06 '13 at 17:24
  • OK, so what is with the down-vote now? Somebody seems to be taking exception to my highly up-voted answers today. – juanchopanza Jul 06 '13 at 17:27
  • 1
    I don't know, but I'm upvoting - 4 more lame downvotes covered :) – SomeWittyUsername Jul 06 '13 at 17:55
  • Note that the second version won't work if you replace `a.size()` by a `const int n` for example. `for(auto i = decltype(n){0}; i < n; i++)` fixes that case – Ragnar Jun 23 '15 at 11:28
  • I agree range based loop is often cleaner, but when you need an index do people really prefer `decltype(a.size()) i = 0;` to `size_t i = 0;` ? In practice, isn't `size_t` always the right index type? Have people really found cases where they had `size_t i` and made changes to a container interface such that `size_t` no longer works and they wish (from a maintainability perspective) that they had used a more abstract type like `decltype(a.size()) i = 0;` ? To me, `size_t` is more concise and more clear and container index types never change. – JDiMatteo Sep 16 '15 at 17:05
  • 1
    @JDiMatteo I agree that `detlype` isn't very clear. Unfortunately, `size_t` isn't guaranteed to be the right type, otherwise the containers wouldn't need to define a `size_type`. So I would use it in generic code, if I want to be sure to use the right type. But I don't recall having had to do that so far... – juanchopanza Sep 16 '15 at 17:23
19

Depending on what you want to do inside the loop and the capabilities of your compiler, range-based for loop might be a better solution.

All of your presented solutions are not bad in most situations, with minor differences Your first solution is actually worse choice and that's exactly what your compiler tells you. Second solution is better but if you want to avoid directly defining types for simplicity or some future changes, you can do the following:

auto n = a.size();
for (decltype(n) i = 0; i < n; i++) {
}

This way you bind the i and n types to always match each other.

SomeWittyUsername
  • 18,025
  • 3
  • 42
  • 85
6

If you used the correct literal, you'd be fine: 0U. auto sees a literal of type int, so that is the type of i. Add the U and it will see an unsigned int literal instead. Otherwise, you'd want to make use of decltype as others suggested, especially since sizeof(size_t) may be greater than sizeof(int) (it is on Windows, OS X, etc. if running in 64-bit long mode).

  • 3
    Is `sizeof(0U)` always `sizeof(size_t)` per the standard? – Flexo Jul 06 '13 at 17:28
  • @Flexo: Post edited to reflect that and encourage acceptance of another answer. –  Jul 06 '13 at 17:31
  • -1. The first half of this answer is wrong as Flexo says. And the second half basically says "do as the other answers say". If you want to "encourage acceptance of another answer", you can delete this one. – interjay Jul 08 '13 at 09:02
  • 1
    +1. Just learned of `auto i= 0U`, and the caveat in using it. @ChronoKitsune and @Flexo show it is a _valid_ but not _optimal_ solution for OP. Cleaner than `decltype(a.size()) i=0` in trivial code. – Garrick Nov 16 '13 at 15:37
5

Trying to be const-correct whenever possible, I usually write:

const auto n(a.size());
for (auto i = decltype(n){0}; i < n; ++i)
{
}

It isn't very concise, but it's clear that you want a variable initialized to 0 of n's type (and n is const).

manlio
  • 18,345
  • 14
  • 76
  • 126
2

For discussion:

auto n = a.size();
for (auto i = n-n; i<n; ++i) {
}

Note that for types smaller than int, the substraction result widens to int (called integer promotion).

Meinersbur
  • 7,881
  • 1
  • 27
  • 29
1

Here's a simple & cleaner solution to make it work.

for(auto i: a)
{
}
Kartik Chauhan
  • 2,779
  • 5
  • 28
  • 39
0

Using unsigned types would pose a problem in case of expressions like the following:

for (auto i = 0u; i < a.size() - k; ++i) ...

I propose two options instead. The first one (editors choice):

for (auto i = 0; i < static_cast<int>(a.size()); ++i) ...

and if you are fine with using a type which is bigger in size than size_t:

for (auto i = 0ll; i < a.size(); ++i) ...

Otherwise, if the type of the operand with signed integer type can represent all of the values of the type of the operand with unsigned integer type, the operand with unsigned integer type shall be converted to the type of the operand with signed integer type. [expr.arith.conv]

Yola
  • 18,496
  • 11
  • 65
  • 106
0
for ( decltype (a.size()) i = 0; i < a.size(); i++) {...}

I hope this helps.

James Risner
  • 5,451
  • 11
  • 25
  • 47
  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/34008498) – Benjamin Buch Mar 14 '23 at 00:55
-2
for(auto n = a.size(), i = 0; i != n; ++i) {
}

...is probably the cleanest solution if you need the to access the index, as well as the actual element.

Update:

for(auto n = a.size(), i = n*0; i != n; ++i) {
}

Would be a workaround for Richard Smiths comment, although it doesn't look that clean anymore.

Viktor Sehr
  • 12,825
  • 5
  • 58
  • 90
  • 4
    This is not correct: in an `auto` declaration that declares multiple variables, the `auto` is deduced independently for each variable and the code is ill-formed if the deduced types are not the same. – Richard Smith Jul 06 '13 at 21:46