26

please see the following code

struct A { using type = int; };
struct B : private A {};
struct C : B { using base_type = A; };

All of gcc 6.1, clang 3.8, and msvc 2015 update 3 refuse to compile this, as A is not an accessible name inside C since A is a private base of B. It seems that gcc thinks A in using base_type = A refers to the default constructor of A. msvc and clang seem not.

Perhaps the compilation error is due to the injection of names triggered by inheritances (because modifying using base_type = A into using base_type = ::A make all the compilers work fine), but I want to know if this weird error is what the standard says.

More concretely,

  1. As I understood, not like A::type, A is just a class name (although gcc misinterprets it as a function name) which is introduced to C not inside A nor B. Why this name is considered private to B?
  2. Should this compilation error be considered a bug, or is an edge case of the specifications of the standard?
Piotr Skotnicki
  • 46,953
  • 7
  • 118
  • 160
Junekey Jeon
  • 1,496
  • 1
  • 11
  • 18
  • 1
    I am guessing this is due to how name lookup for `A` inside `C` works. First it checks to find if anything is declared with a name `A` in the scope of `C` before `using`. Since it does not find one, it is checking it in the scope of `B` since it's the Base class. And in case it does not find `A` in `B`s scope, it will look out in the `global namespace`. But somehow the `private inheritance` of `A` by `B` is getting stopped at the second lookup i.e inside the scope of `B`. Since it works using `fully qualified` name, that makes me think that the real issue must be on the same lines. – Arunmu Jul 04 '16 at 08:24
  • 4
    http://eel.is/c++draft/class.access.spec#5 seems relevant – Piotr Skotnicki Jul 04 '16 at 08:27
  • @PiotrSkotnicki Thank you, it directly answers the question. But, can you give me the rational behind this rule? – Junekey Jeon Jul 04 '16 at 08:36
  • @PiotrSkotnicki Well, it's okay. I think I somewhat understood the things. Thank you! – Junekey Jeon Jul 04 '16 at 08:43

2 Answers2

28

According to the rule of unqualified name lookup:

(emphasis mine)

For an unqualified name, that is a name that does not appear to the right of a scope resolution operator ::, name lookup examines the scopes as described below, until it finds at least one declaration of any kind, at which time the lookup stops and no further scopes are examined.

So the name A will be found firstly at the base class scope, the name in the global namespace won't be considered here. After that, access right checking is performed and then compile failed.

And ::A specifies the name in global scope and solves the issue, which making it a qualified name lookup.

songyuanyao
  • 169,198
  • 16
  • 310
  • 405
2

Posting my comment as answer (seems like an answer more than a comment):

I am guessing this is due to how name lookup for Ainside C works. First it checks to find if anything is declared with a name A in the scope of C before using. Since it does not find one, it is checking it in the scope of B since it's the Base class. And in case it does not find A in Bs scope, it will look out in the global namespace. But somehow the private inheritance of A by B is getting stopped at the second lookup i.e inside the scope of B. Since it works using fully qualified name, that makes me think that the real issue must be on the same lines.

Arunmu
  • 6,837
  • 1
  • 24
  • 46