局部变量可以与命名空间同名吗?

时间:2015-04-21 14:26:36

标签: c++ namespaces language-lawyer

GCC,clang和VS2013编译下面的代码段:

namespace A{}
int main()
{
    int A;
}

然而[namespace.alias] / 4说明如下:

  

namespace-name namespace-alias 不得声明为   同一声明区域中的任何其他实体的名称

[basic.scope.declarative] / 1说:

  

在名为a的程序文本的某些部分中引入了每个名称   声明性区域,这是该名称​​有效的程序的最大部分,也就是说,该名称可以用作   一个不合格的名称,指的是同一个实体。

也就是说,我的印象是int中的main()变量与名称空间A的名称不同。注意到[basic.scope.declarative] / 2中的例子似乎证实了这一点

  

第一个j的声明区域包括整个示例。

4 个答案:

答案 0 :(得分:5)

从[basic.scope.declarative]来看,“声明区域”的定义是:

  

每个名称都在程序文本的某些部分中引入,称为声明性区域,这是最大的部分   该名称有效的程序,即该名称可用作非限定名称的程序   引用同一个实体。

限制是,强调我的:

  

在单个声明区域中给出一组声明 ,每个声明指定相同的非限定名称
   - 它们都应引用同一实体,或全部引用功能和功能模板

回到你的例子。如果我们注释两个声明性区域,我们有:

namespace A{}    + region #1
                 |
int main()       |           +
{                |           |
    int A;       |           | region #2               
                 |           |
}                +           +

namespace A(#1)和int A(#2)的声明性区域不同(第二个是第一个的严格子集,但无关紧要)。由于它们不同,因此对单一名称的限制不适用。 #2中有一个A,#1中有一个A

但是,如果我们将int A移到同一声明区域中:

namespace A {}     +   the only declarative region. even though the
int A;             |   potential scope of "int A" does not include
                   |   "namespace A", the declarative region does.
int main() {       |   The intent of this is expressed in the example
                   |   in [basic.scope.declarative]/2:
                   |        int main() {
                   |            int i = j, j;
                   |            j = 42;
                   |        }
                   |
                   |   "The declarative region of the [j] includes all 
                   |    the text between { and }, but its potential scope
}                  +    excludes the declaration of i."

这会违反[basic.scope.declarative] / 4,并且gcc和clang都正确拒绝代码:

  

错误:将“A”重新定义为不同类型的符号

请注意,正如Vaughn Cato指出的那样,声明区域的措辞有active defect report

答案 1 :(得分:2)

你提到的第一个引用 [namespace.alias] / 4 实际上是为了覆盖扩展名称空间,并且是缺陷报告的主题,随后被删除并替换为更具体的措辞。我们可以从DR 1795看到:

  

根据7.3.1 [namespace.def]第2段,

     
    

原始名称空间定义中的标识符先前不应在声明区域中定义     出现原始名称空间定义。

  
     

显然,这个要求的目的是说,给定的   声明

namespace N { }
namespace N { }
     

第二个声明应被视为   extension-namespace-definition而不是   原始名称空间定义,因为3.3.1中的一般规则   [basic.scope.declarative]涵盖标识符所具有的情况   以前被声明为命名空间以外的东西。

并告诉我们3.3.1 [basic.scope.declarative]涵盖了您所指的案例,它在段落1中执行:

  

每个名称都在程序文本的某些部分中引入,称为声明性区域,这是最大的部分   该名称有效的程序,即该名称可用作非限定名称的程序   引用同一个实体。通常,每个特定名称仅在某些可能不连续的情况下有效   程序文本的一部分称为其范围。要确定声明的范围,有时很方便   提及声明的潜在范围。声明的范围与其潜在范围相同   除非潜在范围包含另一个同名声明。在那种情况下,潜在的范围   内部(包含)声明区域中的声明被排除在声明的范围之外   在外部(包含)声明性区域。

3

  

在单个声明性区域中给出一组声明,每个声明都指定相同的非限定名称,

     
      
  • 它们都应引用同一个实体,或者全部引用功能和功能模板;
  •   

答案 2 :(得分:0)

如果你看一下3.3.1(1)

下面的例子3.3.1(2)
int j = 24;
int main() {
    int i = j, j;
    j = 42;
}

注意到

  

标识符j被声明为名称两次(并使用两次)。第一个j的声明区域包括整个示例。 第一个j的潜在范围在j之后立即开始并延伸到程序的结尾,但其(实际)范围排除了和之间的文本。第二个j的声明性区域j的声明(分号前面的j)包括{和}之间的所有文本,但其潜在范围不包括i的声明。 j的第二个声明的范围与其潜在范围相同。

注意它所说的名称的范围。强调我的。

因此,在程序的全局空间中,您有一个名称为A的名称空间。然后输入main()的范围,namespace A仍然是有效名称,直到看到int A的声明为止。一旦在main范围内发生,名称空间A将被隐藏,对A的任何无限制调用将被声明为int

答案 3 :(得分:0)

int A有效的最大范围是main的整个范围,因此其声明区域为main。命名空间在全局范围内有效,因此不在同一声明范围内。请注意,虽然范围重叠,但它们不是相同的范围。鉴于您的标准报价,该代码看起来对我有用。