使用 using 声明时,非限定名称查找如何工作?
How does unqualified name lookup work when using using-declarations?
根据 c++ 标准,这是良构还是良构?
namespace M { struct i {}; }
namespace N { static int i = 1; }
using M::i;
using N::i;
int main() { sizeof (i); }
Clang 拒绝,GCC 接受。
根据[namespace.udir-6] (http://eel.is/c++draft/basic.namespace#namespace.udir-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.
我们应该如何解读?请记住,每个 using 声明都通过 [namespace.udecl]p1 (http://eel.is/c++draft/namespace.udecl#1):
声明一个名称
A using-declaration introduces a name into the declarative region in
which the using-declaration appears.
using-declaration:
using typename
opt nested-name-specifier unqualified-id ;
The member name specified in a using-declaration is declared in the
declarative region in which the using-declaration appears. [ Note:
Only the specified name is so declared; specifying an enumeration name
in a using-declaration does not declare its enumerators in the
using-declaration's declarative region. — end note ] If a
using-declaration names a constructor ([class.qual]), it implicitly
declares a set of constructors in the class in which the
using-declaration appears ([class.inhctor]); otherwise the name
specified in a using-declaration is a synonym for a set of
declarations in another namespace or class.
所以我们有 4 个名称 i 的声明。
sizeof(i)
中 i
的非限定名称查找找到了哪些?
是否只找到同一个命名空间(全局命名空间)中的 using M::i;
和 using N::i;
所以程序是良构的?
还是它只找到位于不同命名空间的 struct i {};
和 static int i = 1;
,所以程序格式错误?
或者我们有其他选择吗?
N4527 [7.3.3p13]:
Since a using-declaration is a declaration, the restrictions on
declarations of the same name in the same declarative region (3.3)
also apply to using-declarations. [ Example:
namespace A {
int x;
}
namespace B {
int i;
struct g { };
struct x { };
void f(int);
void f(double);
void g(char); // OK: hides struct g
}
void func() {
int i;
using B::i; // error: i declared twice
void f(char);
using B::f; // OK: each f is a function
f(3.5); // calls B::f(double)
using B::g;
g(’a’); // calls B::g(char)
struct g g1; // g1 has class type B::g
using B::x;
using A::x; // OK: hides struct B::x
x = 99; // assigns to A::x
struct x x1; // x1 has class type B::x
}
—end example ]
请注意两个不同 x
的 using-declarations - 这与您的示例相同。
你的第一句话是指 using-directives,而不是 using-declarations。
sizeof(i)
中 i
的非限定名称查找在全局命名空间中找到 i
。由于它们是同一范围内的声明,根据 [3.3.10p2](下面引用),变量 i
隐藏了 struct
.
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. 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.
因此,代码格式正确,Clang 拒绝它是错误的。
MSVC(12 和 14)接受示例。
基本上,将 using-declaration 引入的名称视为某个实体的另一个名称,该名称也在其他地方命名([=33 指定的位置) =]nested-name-specifier of the qualified-id in the using-declaration)。这与 using-directive 的作用不同;我倾向于将 using-directives 视为 "name lookup tweaks".
已经有了答案,但为了说明为什么您的直觉不正确,您引用了:
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.
但在示例中,我们有:
namespace M {
struct i {}; // declares M::i, entity class type
}
namespace N {
static int i = 1; // declares N::i, entity variable
}
using M::i; // declares ::i, synonym of M::i
using N::i; // declares ::i, synonym of N::i
// hides (*) the other ::i
int main() {
sizeof (i);
}
为了详细说明 (*)
,我们在全局命名空间 ::
中有两个 i
声明。来自 [basic.scope.hiding]:
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. 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
,class 被隐藏( 与 的顺序无关 using-declarations!),而sizeof(i)
指的是::i
,它是N::i
的同义词。两个 i
都在 相同的 命名空间 (::
) 中,这就是为什么您的引述不适用的原因。这与您的 不同,您 using-directives 而不是:
using namespace M;
using namespace N;
在两个不同的命名空间中可以找到 i
,指的是两个不同的非功能实体。因此,错误。在这里,Clang 是错误的,而 GCC 是正确的。
根据 c++ 标准,这是良构还是良构?
namespace M { struct i {}; }
namespace N { static int i = 1; }
using M::i;
using N::i;
int main() { sizeof (i); }
Clang 拒绝,GCC 接受。
根据[namespace.udir-6] (http://eel.is/c++draft/basic.namespace#namespace.udir-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.
我们应该如何解读?请记住,每个 using 声明都通过 [namespace.udecl]p1 (http://eel.is/c++draft/namespace.udecl#1):
声明一个名称A using-declaration introduces a name into the declarative region in which the using-declaration appears.
using-declaration:
using typename
opt nested-name-specifier unqualified-id;
The member name specified in a using-declaration is declared in the declarative region in which the using-declaration appears. [ Note: Only the specified name is so declared; specifying an enumeration name in a using-declaration does not declare its enumerators in the using-declaration's declarative region. — end note ] If a using-declaration names a constructor ([class.qual]), it implicitly declares a set of constructors in the class in which the using-declaration appears ([class.inhctor]); otherwise the name specified in a using-declaration is a synonym for a set of declarations in another namespace or class.
所以我们有 4 个名称 i 的声明。
sizeof(i)
中 i
的非限定名称查找找到了哪些?
是否只找到同一个命名空间(全局命名空间)中的 using M::i;
和 using N::i;
所以程序是良构的?
还是它只找到位于不同命名空间的 struct i {};
和 static int i = 1;
,所以程序格式错误?
或者我们有其他选择吗?
N4527 [7.3.3p13]:
Since a using-declaration is a declaration, the restrictions on declarations of the same name in the same declarative region (3.3) also apply to using-declarations. [ Example:
namespace A { int x; } namespace B { int i; struct g { }; struct x { }; void f(int); void f(double); void g(char); // OK: hides struct g } void func() { int i; using B::i; // error: i declared twice void f(char); using B::f; // OK: each f is a function f(3.5); // calls B::f(double) using B::g; g(’a’); // calls B::g(char) struct g g1; // g1 has class type B::g using B::x; using A::x; // OK: hides struct B::x x = 99; // assigns to A::x struct x x1; // x1 has class type B::x }
—end example ]
请注意两个不同 x
的 using-declarations - 这与您的示例相同。
你的第一句话是指 using-directives,而不是 using-declarations。
sizeof(i)
中 i
的非限定名称查找在全局命名空间中找到 i
。由于它们是同一范围内的声明,根据 [3.3.10p2](下面引用),变量 i
隐藏了 struct
.
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. 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.
因此,代码格式正确,Clang 拒绝它是错误的。
MSVC(12 和 14)接受示例。
基本上,将 using-declaration 引入的名称视为某个实体的另一个名称,该名称也在其他地方命名([=33 指定的位置) =]nested-name-specifier of the qualified-id in the using-declaration)。这与 using-directive 的作用不同;我倾向于将 using-directives 视为 "name lookup tweaks".
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.
但在示例中,我们有:
namespace M {
struct i {}; // declares M::i, entity class type
}
namespace N {
static int i = 1; // declares N::i, entity variable
}
using M::i; // declares ::i, synonym of M::i
using N::i; // declares ::i, synonym of N::i
// hides (*) the other ::i
int main() {
sizeof (i);
}
为了详细说明 (*)
,我们在全局命名空间 ::
中有两个 i
声明。来自 [basic.scope.hiding]:
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. 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
,class 被隐藏( 与 的顺序无关 using-declarations!),而sizeof(i)
指的是::i
,它是N::i
的同义词。两个 i
都在 相同的 命名空间 (::
) 中,这就是为什么您的引述不适用的原因。这与您的
using namespace M;
using namespace N;
在两个不同的命名空间中可以找到 i
,指的是两个不同的非功能实体。因此,错误。在这里,Clang 是错误的,而 GCC 是正确的。