当非限定名称查找涉及使用指令时 [basic.scope.hiding]p2 的解释
Interpretation of [basic.scope.hiding]p2 when unqualified name lookup involves using-directives
c++中隐藏了两种名字:
1) 正常名称隐藏:[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)隐藏在[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.
我很想知道在执行非限定名称查找时名称隐藏如何与 using 指令交互。
对于第一种名称,隐藏行为非常清楚。这是因为 [basic.scope.hiding]p1 已根据 [basic.lookup.unqual] (http://eel.is/c++draft/basic.lookup.unqual)
部分中的规则重新表述
第二种隐藏名字的方式没有做同样的事情。所以现在出现以下问题:
*) 这第二种类型的名称隐藏应该如何与涉及 using-directives 的非限定名称查找交互?
我在标准的其他地方找到 [namespace.udir]p2 (http://eel.is/c++draft/namespace.udir#2),我认为这是回答这个问题的关键:
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 ]
将此规则的 as if 部分应用于 [basic.scope.hiding]p1 与 [basic.lookup.unqual] 部分中的规则保持一致。此应用程序也符合 [basic.scope.hiding]p4 (http://eel.is/c++draft/basic.scope.hiding#4) 所以这看起来很有希望。
因此,我认为我们可以通过类似地将 [namespace.udir]p2 的 as if 部分应用于 [basic.scope.hiding 来回答问题 *) ]p2。此应用程序也符合 [basic.scope.hiding]p4。我认为这也是对c++标准最自然、最不复杂的解释。
然而问题在于,Clang 和 GCC 并没有做出与我相同的解释。例如:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
根据我的解释,这个程序应该是合式的,i
应该作为整型变量来查找。 Clang 和 GCC 都不同意这一点,因为名称查找含糊不清。
在 Clang 的情况下,这种更复杂的解释会导致以下错误:
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); }
没有报错,但有变化
using namespace P;
using namespace Q;
进入
using namespace Q;
using namespace P;
我们得到名称查找歧义错误。 GCC 至少在这里是一致的。
我是否正确解释了 c++ 标准?
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
这是错误的格式。 §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.
这同样适用于您的第二个示例。请注意,名称隐藏规则适用于例如
struct A {} A;
…不适用于您的情况,因为两个 i
是在不同的范围内声明的。另外,
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.
也是无关紧要的,因为名称查找产生的任何歧义,如您使用 i
的示例,都在 after lookup 中处理 - 例如前面提到的 §7.3.4/6.
我认为这里的关键短语是:
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.
在这个例子中:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
两个 i
都在不同的非嵌套范围内声明,因此没有隐藏。名称查找发现它们 就好像 它们是在 ::
中声明的,但这不是隐藏规则所规定的。
否则,我们有,从[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;
::
中没有明确的声明,所以这段代码格式错误,错误正确。另一个例子也是如此,所以事实上有一些 using-declaration clang 编译它的顺序是一个错误。
虽然这是非规范的,但 [namespace.udir] 中有一个示例可以清楚地说明这一解释:
[ 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 ]
c++中隐藏了两种名字:
1) 正常名称隐藏:[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)隐藏在[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.
我很想知道在执行非限定名称查找时名称隐藏如何与 using 指令交互。
对于第一种名称,隐藏行为非常清楚。这是因为 [basic.scope.hiding]p1 已根据 [basic.lookup.unqual] (http://eel.is/c++draft/basic.lookup.unqual)
部分中的规则重新表述第二种隐藏名字的方式没有做同样的事情。所以现在出现以下问题:
*) 这第二种类型的名称隐藏应该如何与涉及 using-directives 的非限定名称查找交互?
我在标准的其他地方找到 [namespace.udir]p2 (http://eel.is/c++draft/namespace.udir#2),我认为这是回答这个问题的关键:
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 ]
将此规则的 as if 部分应用于 [basic.scope.hiding]p1 与 [basic.lookup.unqual] 部分中的规则保持一致。此应用程序也符合 [basic.scope.hiding]p4 (http://eel.is/c++draft/basic.scope.hiding#4) 所以这看起来很有希望。
因此,我认为我们可以通过类似地将 [namespace.udir]p2 的 as if 部分应用于 [basic.scope.hiding 来回答问题 *) ]p2。此应用程序也符合 [basic.scope.hiding]p4。我认为这也是对c++标准最自然、最不复杂的解释。
然而问题在于,Clang 和 GCC 并没有做出与我相同的解释。例如:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
根据我的解释,这个程序应该是合式的,i
应该作为整型变量来查找。 Clang 和 GCC 都不同意这一点,因为名称查找含糊不清。
在 Clang 的情况下,这种更复杂的解释会导致以下错误:
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); }
没有报错,但有变化
using namespace P;
using namespace Q;
进入
using namespace Q;
using namespace P;
我们得到名称查找歧义错误。 GCC 至少在这里是一致的。
我是否正确解释了 c++ 标准?
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
这是错误的格式。 §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.
这同样适用于您的第二个示例。请注意,名称隐藏规则适用于例如
struct A {} A;
…不适用于您的情况,因为两个 i
是在不同的范围内声明的。另外,
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.
也是无关紧要的,因为名称查找产生的任何歧义,如您使用 i
的示例,都在 after lookup 中处理 - 例如前面提到的 §7.3.4/6.
我认为这里的关键短语是:
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.
在这个例子中:
namespace N { static int i = 1; }
namespace M { struct i {}; }
using namespace M;
using namespace N;
int main() { sizeof(i); }
两个 i
都在不同的非嵌套范围内声明,因此没有隐藏。名称查找发现它们 就好像 它们是在 ::
中声明的,但这不是隐藏规则所规定的。
否则,我们有,从[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;
::
中没有明确的声明,所以这段代码格式错误,错误正确。另一个例子也是如此,所以事实上有一些 using-declaration clang 编译它的顺序是一个错误。
虽然这是非规范的,但 [namespace.udir] 中有一个示例可以清楚地说明这一解释:
[ 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 ]