使用命名空间时的全局范围解析
Global scope resolution in the presence of using namespace
考虑以下代码:
namespace foo {
namespace bar {
class foo {};
}
class baz {};
}
using namespace foo::bar;
::foo::baz mybaz;
此代码有效吗?
还是 ::foo
含糊不清?
或者 ::foo
是指 class foo
,这样就没有 ::foo::baz
.
说到编译器,gcc 6.1.1
似乎是后者:
scope.cpp:9:8: error: ‘baz’ in ‘class foo::bar::foo’ does not name a type
::foo::baz mybaz;
^~~
另一方面,gcc 5.3.1
、clang 3.8.0
和英特尔编译器 16.0.3 不会产生任何警告或错误。
我怀疑在C++14标准的3.4.3.2.2下,这应该是有效的,没有歧义,但我不太确定。
编辑:此外,对于 foo::baz mybaz
只有 clang 报告不明确的错误。
[namespace.qual] 相当简单:
1 If the nested-name-specifier of a qualified-id nominates a namespace (including the case where the nested-name-specifier is ::
, i.e., nominating the global namespace), the name specified after the nested-name-specifier is looked up in the scope of the namespace. The names in a template-argument of a template-id are looked up in the context in which the entire postfix-expression occurs.
2 For a namespace X
and name m
, the namespace-qualified lookup set S(X
,m
) is defined as follows: Let S0(X
,m
) be the set of all declarations of m
in X
and the inline namespace set of X
(7.3.1). If S0(X
,m
) is not empty, S(X
,m
) is S0(X
,m
); otherwise, S(X
,m
) is the union of S(Ni,m
) for all namespaces Ni nominated by using-directives in X
and its inline namespace set.
3 Given X::m
(where X
is a user-declared namespace), or given ::m
(where X
is the global namespace), if S(X
,m
) is the empty set, the program is ill-formed. Otherwise, if S(X
,m
) has exactly one member, or if the context of the reference is a using-declaration (7.3.3), S(X
,m
) is the required set of declarations of m
. Otherwise if the use of m
is not one that allows a unique declaration to be chosen from S(X
,m
), the program is ill-formed.
::foo
是具有 nested-name-specifier ::
的 qualified-id,因此名称foo
在全局范围内查找。
S0(::
,foo
) 包含 namespace foo
的单个声明,因为没有 [=47 的其他声明=] 在命名空间中,它没有内联命名空间。因为S0(::
,foo
)不为空,所以S(::
,foo
)是S0(::
,foo
)。 (请注意,由于 S0(::
,foo
) 不为空,因此从不检查通过 using 指令指定的命名空间。)
由于 S(::
,foo
) 只有一个元素,该声明用于 ::foo
.
名称 ::foo::baz
因此是 qualified-id with nested-name-specifier ::foo
指定命名空间。在命名空间 ::foo
中再次有一个 baz
的声明,因此名称 ::foo::baz
指的是 class baz
声明。
您在 GCC 6+ 中观察到的行为实际上是一个错误,归档为 GCC PR 71173。
编辑:foo::baz
在全局范围内出现时的查找,a la:
foo::baz bang;
首先需要查找 foo
作为非限定名称。 [basic.lookup.qual]/1 说这个查找只看到“专门化为类型的名称空间、类型和模板”。 [basic.scope.namespace]/1 告诉我们有关命名空间成员及其范围的信息:
The declarative region of a namespace-definition is its namespace-body. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name’s point of declaration onwards; and for each using-directive that nominates the member’s namespace, the member’s potential scope includes that portion of the potential scope of the using-directive that follows the member’s point of declaration.
[basic.lookup.unqual]/4告诉我们namespace foo
的声明是可见的:
A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.
并且第 2 段说 class foo
在这里也可见:
The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
由于发现来自不同名称空间的不同 foo
实体的两个声明,[namespace.udir]/6 告诉我们 foo
的使用格式错误:
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.
我们对 foo::baz
的名称查找在到达 baz
之前就终止了。
考虑以下代码:
namespace foo {
namespace bar {
class foo {};
}
class baz {};
}
using namespace foo::bar;
::foo::baz mybaz;
此代码有效吗?
还是 ::foo
含糊不清?
或者 ::foo
是指 class foo
,这样就没有 ::foo::baz
.
说到编译器,gcc 6.1.1
似乎是后者:
scope.cpp:9:8: error: ‘baz’ in ‘class foo::bar::foo’ does not name a type
::foo::baz mybaz;
^~~
另一方面,gcc 5.3.1
、clang 3.8.0
和英特尔编译器 16.0.3 不会产生任何警告或错误。
我怀疑在C++14标准的3.4.3.2.2下,这应该是有效的,没有歧义,但我不太确定。
编辑:此外,对于 foo::baz mybaz
只有 clang 报告不明确的错误。
[namespace.qual] 相当简单:
1 If the nested-name-specifier of a qualified-id nominates a namespace (including the case where the nested-name-specifier is
::
, i.e., nominating the global namespace), the name specified after the nested-name-specifier is looked up in the scope of the namespace. The names in a template-argument of a template-id are looked up in the context in which the entire postfix-expression occurs.2 For a namespace
X
and namem
, the namespace-qualified lookup set S(X
,m
) is defined as follows: Let S0(X
,m
) be the set of all declarations ofm
inX
and the inline namespace set ofX
(7.3.1). If S0(X
,m
) is not empty, S(X
,m
) is S0(X
,m
); otherwise, S(X
,m
) is the union of S(Ni,m
) for all namespaces Ni nominated by using-directives inX
and its inline namespace set.3 Given
X::m
(whereX
is a user-declared namespace), or given::m
(whereX
is the global namespace), if S(X
,m
) is the empty set, the program is ill-formed. Otherwise, if S(X
,m
) has exactly one member, or if the context of the reference is a using-declaration (7.3.3), S(X
,m
) is the required set of declarations ofm
. Otherwise if the use ofm
is not one that allows a unique declaration to be chosen from S(X
,m
), the program is ill-formed.
::foo
是具有 nested-name-specifier ::
的 qualified-id,因此名称foo
在全局范围内查找。
S0(::
,foo
) 包含 namespace foo
的单个声明,因为没有 [=47 的其他声明=] 在命名空间中,它没有内联命名空间。因为S0(::
,foo
)不为空,所以S(::
,foo
)是S0(::
,foo
)。 (请注意,由于 S0(::
,foo
) 不为空,因此从不检查通过 using 指令指定的命名空间。)
由于 S(::
,foo
) 只有一个元素,该声明用于 ::foo
.
名称 ::foo::baz
因此是 qualified-id with nested-name-specifier ::foo
指定命名空间。在命名空间 ::foo
中再次有一个 baz
的声明,因此名称 ::foo::baz
指的是 class baz
声明。
您在 GCC 6+ 中观察到的行为实际上是一个错误,归档为 GCC PR 71173。
编辑:foo::baz
在全局范围内出现时的查找,a la:
foo::baz bang;
首先需要查找 foo
作为非限定名称。 [basic.lookup.qual]/1 说这个查找只看到“专门化为类型的名称空间、类型和模板”。 [basic.scope.namespace]/1 告诉我们有关命名空间成员及其范围的信息:
The declarative region of a namespace-definition is its namespace-body. Entities declared in a namespace-body are said to be members of the namespace, and names introduced by these declarations into the declarative region of the namespace are said to be member names of the namespace. A namespace member name has namespace scope. Its potential scope includes its namespace from the name’s point of declaration onwards; and for each using-directive that nominates the member’s namespace, the member’s potential scope includes that portion of the potential scope of the using-directive that follows the member’s point of declaration.
[basic.lookup.unqual]/4告诉我们namespace foo
的声明是可见的:
A name used in global scope, outside of any function, class or user-declared namespace, shall be declared before its use in global scope.
并且第 2 段说 class foo
在这里也可见:
The declarations from the namespace nominated by a using-directive become visible in a namespace enclosing the using-directive; see 7.3.4. For the purpose of the unqualified name lookup rules described in 3.4.1, the declarations from the namespace nominated by the using-directive are considered members of that enclosing namespace.
由于发现来自不同名称空间的不同 foo
实体的两个声明,[namespace.udir]/6 告诉我们 foo
的使用格式错误:
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.
我们对 foo::baz
的名称查找在到达 baz
之前就终止了。