Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[namespace.def.general] p6 Clarify "enclosing" and inserted using-directive #4556

Closed
xmh0511 opened this issue Mar 25, 2021 · 9 comments · Fixed by #4562
Closed

[namespace.def.general] p6 Clarify "enclosing" and inserted using-directive #4556

xmh0511 opened this issue Mar 25, 2021 · 9 comments · Fixed by #4562
Assignees

Comments

@xmh0511
Copy link
Contributor

xmh0511 commented Mar 25, 2021

The first place that needs to be precise is

Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace.

Since the following vague(misleading) sentence has been removed in the current draft

The enclosing namespace set of O is the set of namespaces consisting of the innermost non-inline namespace enclosing an inline namespace O, together with any intervening inline namespaces.

Presumably, the wording enclosing should assume to have the meaning in English, that is, all namespaces that declared in a namespace A, we would say A enclosing those namespaces.

For the first bullet, Should it be precise to

Members of an inline namespace can be used in most respects as though they were members of the enclosing namespace whose inline namespace set comprises the inline namespace.

it together with the following rule

The inline namespace set of N is the transitive closure of all inline namespaces in N.

clarify this case

namespace A{
  namespace B{
     inline namespace C{
          int v;
     }
  }
}
A::v;  //ill-formed , Although A enclosing C
A::B::v; //well-formed

The second issue is
#1

Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup whenever one of them is, and a using-directive ([namespace.udir]) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace ([namespace.unnamed]).

Is it a bit misleading and useless? According to the statement for lookup rule in the current draft, such a using-directive does not affect the result of the lookup, since the following rule

A search in a scope X for a name N from a program point P is a single search in X for N from P unless X is the scope of a class or class template T

A single search in a scope S for a name N from a program point P finds all declarations that precede P to which any name that is the same as N ([basic.pre]) is bound in S.

Even though in the current standard, the relevant rule does also clearly state this point

When considering an associated namespace N, the lookup is the same as the lookup performed when N is used as a qualifier ([namespace.qual]) except that:

Any using-directives in N are ignored.

And there's a more readable rule in [basic.lookup.argdep] that can instead of the initial sentence of the above rule at #1.

The associated namespaces for a call are the innermost enclosing non-inline namespaces for its associated entities as well as every element of the inline namespace set ([namespace.def]) of those namespaces.

So, Is it necessary to remove the redundant and a bit misleading rule to follow the current draft?

@jensmaurer
Copy link
Member

The paragraph you quoted seems redundant with normative statement elsewhere.
Note dcl.pre p2

Unless otherwise stated, utterances in Clause 9 about components in, of, or contained by a declaration or subcomponent thereof refer only to those components of the declaration that are not nested within scopes nested within the declaration.

As a stretch, this could be interpreted to apply to "enclosing" as well.

Regarding your second issue (about the implicit using-directive), I think this shouldn't have survivied P1787. @opensdh, are you ok with removing "a using-directive ([namespace.udir]) that names the inline namespace is implicitly inserted into the enclosing namespace"?

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 27, 2021

The paragraph you quoted seems redundant with normative statement elsewhere.
Note dcl.pre p2

Unless otherwise stated, utterances in Clause 9 about components in, of, or contained by a declaration or subcomponent thereof refer only to those components of the declaration that are not nested within scopes nested within the declaration.

As a stretch, this could be interpreted to apply to "enclosing" as well.

I would argue here, [dcl.pre p2] presumably applies to the following example

void fun(int(*ptr)());  

For the sentence: the declarator-id in the function declaration is... Here the declarator-id should be fun rather than ptr because in is restricted by [dcl.pre p2].

I think enclosing might be not limited by [dcl.pre p2]. Because namespace or class always introduces a scope. Such as the sentence: the enclosing class is.... What I want to clarify for the first issue is that these members declared in the enclosed inline namespace could be referred to by which enclosing namespace. Again, in the above example, Namespace A enclosing B which in turn enclosing C. However, the member of C can only be referred to by B rather A, that is B in this case is the outermost enclosing namespace that can refer to the member of the enclosed C, i.e, the boundary is B.

@jensmaurer
Copy link
Member

For the first sentence, I'd like to point out that it is vague anyway ("in most respects"). And I think we can fix the sentence by saying " of the innermost enclosing namespace".

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 27, 2021

For the first sentence, I'd like to point out that it is vague anyway ("in most respects"). And I think we can fix the sentence by saying " of the innermost enclosing namespace".

Maybe, of the innermost enclosing non-inline namespace and these intervening enclosing inline namespaces would be more clear.

namespace G{
    namespace A{   // innermost enclosing non-inline namespace
        inline namespace B{  // intervening inline namespace
            inline namespace C{
                int v;
            }
        }
    }
}
G::A::v = 0; // well-formed
G::A::B::v = 0; // well-formed 
G::v = 0; // ill-formed

@jensmaurer
Copy link
Member

The following p7 exactly says that it's transitive, so I don't think we need to say anything special for the multiple-nested-inline namespace case in p6.

@jensmaurer jensmaurer changed the title Clarify bullet 6 of [namespace.def] [namespace.def.general] p6 Clarify "enclosing" and inserted using-directive Mar 27, 2021
@jensmaurer jensmaurer self-assigned this Mar 27, 2021
@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 27, 2021

The following p7 exactly says that it's transitive, so I don't think we need to say anything special for the multiple-nested-inline namespace case in p6.

Well, but the innermost enclosing non-inline namespace is necessary. Like the above example, B is enclosing the namespace of C but it's inline. So, the relevant rule "as though they were members of ...", the boundary for such an enclosing namespace should be innermost non-inline. which is consistent with [basic.lookup.argdep#4]

@jensmaurer
Copy link
Member

Not needed. The innermost enclosing namespace of C is B. Everything that follows is valid and good for B (after all, you can explicitly refer to inline namespaces). But because B is also inline, the rule applies transitively, where A is the enclosing namespace for B. And since you can name C::v as B::v, you can thus also name it as A::v (but not as G::v).

@xmh0511
Copy link
Contributor Author

xmh0511 commented Mar 27, 2021

Not needed. The innermost enclosing namespace of C is B. Everything that follows is valid and good for B (after all, you can explicitly refer to inline namespaces). But because B is also inline, the rule applies transitively, where A is the enclosing namespace for B. And since you can name C::v as B::v, you can thus also name it as A::v (but not as G::v).

Ah, it together with p7 states that meaning. That's concise here. 👍

@xmh0511
Copy link
Contributor Author

xmh0511 commented Nov 4, 2021

@jensmaurer It seems that [namespace.def#general-6] still exists a similar issue.

Specifically, the inline namespace and its enclosing namespace are both added to the set of associated namespaces used in argument-dependent lookup whenever one of them is, and a using-directive ([namespace.udir]) that names the inline namespace is implicitly inserted into the enclosing namespace as for an unnamed namespace ([namespace.unnamed]).

Which "enclosing namespace" does the emphasized wording refer to? Is it the innermost enclosing namespace or something else? According to the subject in this issue, since these properties are transitive, I think "the enclosing namespace" should refer to "the innermost enclosing namespace".

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants