Interpretation of [basic.scope.hiding]p2 when unqualified name lookup involves using-directives

大兔子大兔子 提交于 2019-12-23 12:13:26

问题


There are two types of name hiding in c++:

1) Normal name hiding: [basic.scope.hiding]p1 (http://eel.is/c++draft/basic.scope.hiding#1):

A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class ([class.member.lookup]).

2) The special type of name hiding in [basic.scope.hiding]p2 (http://eel.is/c++draft/basic.scope.hiding#2):

A class name ([class.name]) or enumeration name ([dcl.enum]) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope. If a class or enumeration name and a variable, data member, function, or enumerator are declared in the same scope (in any order) with the same name, the class or enumeration name is hidden wherever the variable, data member, function, or enumerator name is visible.

I'm interested to know about how name hiding interacts with using-directives when unqualified name lookup is performed.

For the first type of name hiding the behaviour is quite clear. This is because [basic.scope.hiding]p1 has been reformulated in terms of the rules in the section [basic.lookup.unqual] (http://eel.is/c++draft/basic.lookup.unqual)

The same has not been done for the second type of name hiding. So the following question now arises:

*) How should this second type of name hiding interact with unqualified name lookup that involves using-directives?

Looking elsewhere in the standard I find [namespace.udir]p2 (http://eel.is/c++draft/namespace.udir#2) and I think this is key to answering this question:

A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup ([basic.lookup.unqual]), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. — end note ]

Applying the as if part of this rule to [basic.scope.hiding]p1 gives consistency with the rules in the section [basic.lookup.unqual]. This application is also consistent with [basic.scope.hiding]p4 (http://eel.is/c++draft/basic.scope.hiding#4) So this looks promising.

Because of this I think we can answer the question *) by similarly applying the as if part of [namespace.udir]p2 to [basic.scope.hiding]p2. This application is also consistent with [basic.scope.hiding]p4. I think this is also the most natural and least complex interpretation of the c++ standard.

The problem however is that Clang and GCC does not make the same interpretation as me. For example:

namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;    
int main() { sizeof(i); }

According to my interpretation this program should be well-formed and i should be looked up as the integer variable. Both Clang and GCC disagree with this by giving a name lookup ambiguity.

In the case of Clang this more complex interpretation leads to the following bug:

namespace N { static int i = 1; }
namespace M { struct i {}; }
namespace P {
    using N::i;
    using M::i;
}
namespace Q { using M::i; }
using namespace P;
using namespace Q;
int main() { sizeof (i); }

Gives no errors, but change

using namespace P;
using namespace Q;

into

using namespace Q;
using namespace P;

and we get name-lookup ambiguity error. GCC is at least consistent here.

Did I interpret the c++ standard correctly?


回答1:


The key phrases here I believe are:

A name can be hidden by an explicit declaration of that same name in a nested declarative region or derived class (10.2).

A class name (9.1) or enumeration name (7.2) can be hidden by the name of a variable, data member, function, or enumerator declared in the same scope.

In this example:

namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;    
int main() { sizeof(i); }

Both is are declared in different, non-nested scopes, so there is no hiding. Name lookup finds them as if they were declared in ::, but that's not what the rule for hiding stipulates.

Otherwise, we have, from [basic.lookup]:

Name lookup shall find an unambiguous declaration for the name (see 10.2). Name lookup may associate more than one declaration with a name if it finds the name to be a function name;

There is no unambiguous declaration in ::, so this code is ill-formed and the error is correct. The same is true for the other example, so the fact that there is some using-declaration ordering for which clang compiles it is a bug.

While this is non-normative, there is an example in [namespace.udir] that makes this interpretation clear:

[ Note: In particular, the name of a variable, function or enumerator does not hide the name of a class or enumeration declared in a different namespace. For example,

namespace A {
    class X { };
    extern "C" int g();
    extern "C++" int h();
}

namespace B {
    void X(int);
    extern "C" int g();
    extern "C++" int h(int);
}

using namespace A;
using namespace B;
void f() {
   X(1); // error: name X found in two namespaces
   g();  // OK: name g refers to the same entity
   h();  // OK: overload resolution selects A::h
}

—end note ]




回答2:


namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;    
int main() { sizeof(i); }

This is ill-formed. §7.3.4/6:

If name lookup finds a declaration for a name in two different namespaces, and the declarations do not declare the same entity and do not declare functions, the use of the name is ill-formed.

The same applies to your second example. Note that the name hiding rule that applies in e.g.

struct A {} A;

…doesn't apply in your case, as the two is are declared in distinct scopes. Also,

During unqualified name lookup ([basic.lookup.unqual]), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.

Is irrelevant as well since any ambiguity that name lookup produces, as in your examples with i, is dealt with after lookup - here in e.g. the aforementioned §7.3.4/6.



来源:https://stackoverflow.com/questions/31702956/interpretation-of-basic-scope-hidingp2-when-unqualified-name-lookup-involves-u

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!