内部命名空间名称与全局命名空间名称匹配时的多义性

Ambiguity when inner namespace name matches a global namespace name

本文关键字:命名空间 多义性 全局 内部      更新时间:2023-10-16

语言律师,注意!

我有以下代码:

namespace conflicting 
{
    struct Foo {};
}
namespace outer
{
    namespace conflicting
    {
        struct Bar {};
    }
}
using namespace outer;
int main()
{
    conflicting::Bar b;
    return 0;
} 

使用 g++ 4.8.2,我在尝试编译时收到以下错误:

t.cpp: In function ‘int main()’:
t.cpp:18:5: error: reference to ‘conflicting’ is ambiguous
     conflicting::Bar b;
     ^
t.cpp:2:1: note: candidates are: namespace conflicting { }
 {
 ^
t.cpp:9:5: note:                 namespace outer::conflicting { }
     {
     ^
t.cpp:18:5: error: reference to ‘conflicting’ is ambiguous
     conflicting::Bar b;
     ^
t.cpp:2:1: note: candidates are: namespace conflicting { }
 {
 ^
t.cpp:9:5: note:                 namespace outer::conflicting { }
     {
     ^
t.cpp:18:22: error: expected ‘;’ before ‘b’
     conflicting::Bar b;

有人可以向我解释为什么会发生此错误(也许参考标准的一部分)?

你用conflicting::限定了一个名字,所以编译器需要去那个范围内寻找Bar......但是哪个范围呢?它可以引用两个不同的,::conflictingouter::conflicting由于 using-指令,可以在没有 outer:: 前缀的情况下引用它们。

快速摘要:要使 X::m 成为限定 id,X 需要唯一地引用单个命名空间。

如果conflicting是"命名命名空间的嵌套名称说明符",conflicting::Bar是限定 id,Bar是"该命名空间的成员的名称(或由 using-指令显示的命名空间成员的名称)"(所有引用都是对 N3337 的引用,所有强调都是我的):

5.1.1 一般规定

  1. 一个 :: 或命名命名空间 (7.3) 的嵌套名称说明符,在这两种情况下,后跟该命名空间成员的名称(或由 using-指令显示的命名空间成员的名称)是限定 id;3.4.3.2 描述了出现在限定 ID 中的命名空间成员的名称查找。结果 是成员。结果的类型是成员的类型。如果成员是函数或变量,则结果为左值,否则为属性值。

第 3.4 节描述了名称查找的过程,该过程要求名称查找找到名称的明确声明(重载函数是例外):

3.4 名称查找

    名称
  1. 查找规则统一适用于所有名称(包括 typedef-names (7.1.3)、命名空间名称 (7.3) 和类名 (9.1)),只要语法允许在特定规则讨论的上下文中使用此类名称。名称查找将名称的使用与该名称的声明 (3.1) 相关联。名称查找应找到名称的明确声明(见 10.2)。如果名称查找发现名称是函数名称,则名称查找可能会将多个声明与名称相关联;声明被称为形成一组重载函数 (13.1)。重载解析 (13.3) 在名称查找成功后发生。访问规则(第 11 条)仅在名称查找和函数重载解析(如果适用)成功后才会被考虑。只有在名称查找、函数重载解析(如果适用)和访问检查成功之后,名称声明才会引入的属性进一步用于表达式处理(第 5 条)。

第 3.4.3.2 节的措辞清楚地表明命名空间必须是唯一的:

3.4.3.2 命名空间成员 [命名空间.qual]

    对于命名空间 X 和名称 m,命名空间限定的查找集 S(X,m
  1. ) 定义如下:设 S'(X,m) 是 X 中 m 的所有声明和 X (7.3.1) 的内联命名空间集的集合。如果 S'(X,m) 不为空,则 S(X,m) 为 S'(X,m);否则,S(X,m) 是 S(N_i,m) 的并集,用于通过 X 中的 using 指令及其内联命名空间集提名的所有命名空间 Ni。

此描述假定 X 是唯一的,因为它没有描述遍历一组可能的命名空间以查找 m 的任何过程。

由于编译器无法确定将哪个conflicting命名空间用作命名空间成员查找的起点,因此会给出错误。

希望有帮助。

哟,这

不需要语言法律!一旦outer命名空间引入当前命名空间(通过using它),它的所有名称都变得可见。所以现在你有一个冲突。

这就是为什么我强烈反对using命名空间的做法。命名空间的发明是有原因的,原因是为了防止此类问题。