A weird behavior of using-declaration
Asked Answered
C

2

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?
Caesarea answered 4/7, 2016 at 8:13 Comment(4)
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 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.Roxanneroxburgh
eel.is/c++draft/class.access.spec#5 seems relevantOsyth
@PiotrSkotnicki Thank you, it directly answers the question. But, can you give me the rational behind this rule?Caesarea
@PiotrSkotnicki Well, it's okay. I think I somewhat understood the things. Thank you!Caesarea
C
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.

Catachresis answered 4/7, 2016 at 8:26 Comment(0)
R
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.

Roxanneroxburgh answered 4/7, 2016 at 8:28 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.