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

时间:2016-02-19 17:32:42

标签: c++

语言律师,关注!

我有以下代码:

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;

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

3 个答案:

答案 0 :(得分:1)

您使用conflicting::限定了名称,因此编译器需要在该范围内查找Bar但是哪个范围?它可以引用两个不同的::conflictingouter::conflicting,由于using指令,它们可以在没有outer::前缀的情况下引用。

答案 1 :(得分:0)

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

conflicting::Bar是一个限定ID,如果conflicting是"一个名称命名空间的嵌套名称说明符"并且Bar是"该命名空间成员的名称(或者命名空间成员的名称由using指令可见)" (所有参考文献都是N3337,所有重点都是我的):

  

5.1.1一般[expr.prim.general]

     
      
  1. A ::或命名命名空间的嵌套名称说明符(7.3),在任何一种情况下都跟着t 该命名空间成员的名称(或名称)使用指令可见的命名空间成员的一部分是一个qualified-id; 3.4.3.2描述了出现在qualified-id中的命名空间成员的名称查找。结果   是会员。结果的类型是成员的类型。如果成员是函数或变量,则结果为左值,否则为prvalue。
  2.   

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

  

3.4名称查找[basic.lookup]

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

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

  

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

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

此描述假设X是唯一的,因为它没有描述迭代一组可能的命名空间来查找m的任何过程。

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

希望有所帮助。

答案 2 :(得分:-1)

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

这就是我强烈讨论using命名空间的做法的原因。命名空间是出于某种原因而发明的,其原因是为了防止这些问题。