Ranged for loop with literal list?

2019-06-17 05:16发布

问题:

In C++11, is it possible to write the following

int ns[] = { 1, 5, 6, 2, 9 };
for (int n : ns) {
   ...
}

as something like this

for (int n : { 1, 5, 6, 2, 9 }) { // VC++11 rejects this form
   ...
}

回答1:

tl;dr: Upgrade your compiler for great success.


Yeah, it's valid.

The definition of ranged-for in [C++11: 6.5.4/1] gives us two variants of syntax for this construct. One takes an expression on the right-hand-side of the :, and the other takes a braced-init-list.

Your braced-init-list deduces (through auto) to a std::initializer_list, which is handy because these things may be iterated over.

[..] for a range-based for statement of the form

for ( for-range-declaration : braced-init-list ) statement

let range-init be equivalent to the braced-init-list. In each case, a range-based for statement is equivalent to

{
   auto && __range = range-init;
   for ( auto __begin = begin-expr,
              __end = end-expr;
        __begin != __end;
        ++__begin ) {
      for-range-declaration = *__begin;
      statement
   }
}

[..]

So, you are basically saying:

auto ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
   // ...
}

(I haven't bothered with the universal reference here.)

which in turn is more-or-less equivalent to:

std::initializer_list<int> ns = { 1, 5, 6, 2, 9 };
for (int n : ns) {
   // ...
}

Now, GCC 4.8 supports this but, since "Visual Studio 11" is in fact Visual Studio 2012, you'll need to upgrade in order to catch up: initialiser lists were not supported at all until Visual Studio 2013.



回答2:

It is possible to use this construction with an initializer list. Simply it seems the MS VC++ you are using does not support it.

Here is an example

#include <iostream>
#include <initializer_list>

int main() 
{
    for (int n : { 1, 5, 6, 2, 9 }) std::cout << n << ' ';
    std::cout << std::endl;

    return 0;
}

You have to include header <initializer_list> because the initializer list in the for statement is converted to std::initializer_list<int>