Why is the code “foo::foo::foo::foob” compiling? [

2020-07-03 04:40发布

问题:

A co-worker accidentally wrote code like this:

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 compiles this.

What's the rule that makes this compile?

回答1:

The injected-class-name is used here,

the name of the class within its own definition acts as a public member type alias of itself for the purpose of lookup (except when used to name a constructor): this is known as injected-class-name

then

foo::
foo::
foo::foob

i.e. foo::foo::foo::foob is same as foo::foob.

And then for (auto x : {foo::foobar, foo::fbar, foo::foob }) is a range-based for loop (since C++11), which iterates on the braced-init-list formed by the 3 enumerators.



回答2:

I changed this code to this:

#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;
}

for loop runs 3 times. output is: "x=1 x=2 x=3".


foo::foo::foo::foob is the same foo::foob. So

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

is the same

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

It means that x is in range { foo::foobar, foo::fbar, foo::foob }