使用using声明时,非限定名称查找如何工作?

时间:2015-07-29 21:10:39

标签: c++ language-lawyer name-lookup using-declaration name-hiding

根据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):

  

如果名称查找找到两个不同的名称声明   名称空间,并且声明不会声明相同的实体   没有声明功能,名称的使用是不正确的。

我们该怎么解释这个?请记住,每个using声明都是通过[namespace.udecl] p1(http://eel.is/c++draft/namespace.udecl#1)声明一个名称:

  

using声明在声明区域中引入了一个名称   其中出现了使用声明。

     

using声明
  using typename opt nested-name-specifier unqualified-id ;

     

在using声明中指定的成员名称在   声明区域,其中出现using声明。 [ 注意:   只声明了指定的名称;指定枚举名称   在using声明中没有声明它的枚举器   using-declaration的声明区域。 - 结束说明]如果是   using-declaration命名一个构造函数([class.qual]),它是隐式的   在类中声明一组构造函数   出现using-declaration([class.inhctor]);否则这个名字   在using声明中指定的是一组的同义词   另一个命名空间或类中的声明。

所以我们有4个名字i的声明。

isizeof(i)的{​​{1}}的无限制名称查找中的哪一项?

它是否只找到同一命名空间(全局命名空间)中的using M::i;using N::i;,以便程序格式正确?

或者它只找到位于不同名称空间的struct i {};static int i = 1;,因此程序格式不正确?

或者我们还有其他选择吗?

2 个答案:

答案 0 :(得分:1)

N4527 [7.3.3p13]:

  

由于 using-declaration 是声明,因此受到限制   同一声明区域中的同名声明(3.3)   也适用于使用声明。 [示例:

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
}
     

- 示例]

请注意两个不同x using-declarations - 它与您的示例相同。

您的第一个引用是指 using-directives ,而不是 using-declarations

isizeof(i)的非限定名称查找在全局命名空间中找到i。由于它们是相同范围内的声明,根据[3.3.10p2](下面引用),变量i隐藏了struct

  

可以通过名称隐藏类名(9.1)或枚举名称(7.2)   在...中声明的变量,数据成员,函数或枚举器   相同的范围。如果是类或枚举名称和变量,则为数据   成员,函数或枚举器在同一范围内声明(在任何范围内)   order)具有相同的名称,隐藏类或枚举名称   变量,数据成员,函数或枚举器名称的位置   可见。

因此,代码格式正确,Clang拒绝它是错误的。

MSVC(12和14)接受了这个例子。

基本上,将 using-declaration 引入的名称视为某个实体的另一个名称,该名称也在其他地方命名(由 nested-name-specifier指定的位置使用声明 qualified-id 。这与 using-directive 的作用不同;我倾向于将 using-directives 视为"名称查找调整"。

答案 1 :(得分:1)

anonymous struct已经有了答案,但为了建立你的直觉不正确的原因,你引用了:

  

如果名称查找在两个不同的名称空间中找到名称的声明,并且声明没有声明相同的实体而且没有声明函数,则名称的使用是错误的。 / p>

但是在这个例子中,我们有:

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]:

  

类名(9.1)或枚举名(7.2)可以通过变量名称,数据成员隐藏,   在同一范围内声明的函数或枚举器。如果是类或枚举名称和变量,则为数据   成员,函数或枚举器在同一范围内(以任何顺序)声明具有相同的名称,即   在变量,数据成员,函数或枚举器名称所在的位置隐藏类或枚举名称   可见。

因此,在同一范围内的两个i中,该类被隐藏(无关 using-declarations 的排序!),以及sizeof(i)::i,它是N::i的同义词。这两个i都位于相同的名称空间(::)中,这就是您的报价不适用的原因。这与您的bogdan不同,后者您使用 using-directives

using namespace M;
using namespace N;

在两个不同的名称空间中可以找到i,指的是两个不同的非功能实体。因此,错误。在这里,Clang错了,GCC是正确的。