Почему код "foo:: foo:: foo:: foob" компилируется?

Сотрудник случайно написал такой код:

struct foo {
  foo() : baz(foobar) {}
  enum bar {foobar, fbar, foob};
  bar baz;
};

void f() {
  for( auto x : { foo::foobar,
                  foo::fbar,
                  foo::
                  foo::
                  foo::foob } );
    // ...
}

GCC 5.1.0 компилирует это.

Какое правило делает этот компилятор?

Ответ 1

Здесь используется имя введенного класса,

имя класса в пределах его собственного определения действует как псевдоним публичного элемента для себя с целью lookup (за исключением при использовании constructor): это известно как имя введенного класса

затем

foo::
foo::
foo::foob

то есть. foo::foo::foo::foob совпадает с foo::foob.

И тогда for (auto x : {foo::foobar, foo::fbar, foo::foob }) является основанный на диапазоне для цикла (начиная с С++ 11), который выполняет итерацию на braced-init-list, сформированный из 3-х перечислений.

Ответ 2

Я изменил этот код на это:

#include <initializer_list>
#include <iostream>
struct foo {
  foo() : baz(foobar) {}
  enum bar {foobar, fbar, foob};
  bar baz;
};

int main() {
  for( auto x : { foo::foobar,
                  foo::fbar,
                  foo::
                  foo::
                  foo::foob } )
                  {
                      std::cout << "x=" << x << std::endl;
                  }
  return 0;
}

для цикла выполняется три раза. выход: "x = 1 x = 2 x = 3".


foo::foo::foo::foob является тем же самым foo::foob. Итак,

for( auto x : { foo::foobar,
                  foo::fbar,
                  foo::
                  foo::
                  foo::foob } )

является тем же самым

for( auto x : { foo::foobar, foo::fbar, foo::foob } )
{
}

Это означает, что x находится в диапазоне { foo::foobar, foo::fbar, foo::foob }