2

根据 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-declaration 都通过 [namespace.udecl]p1 ( http://eel.is/c++draft/namespace.udecl#1 ) 声明一个名称:

using-declaration 将名称引入到 using-declaration 出现的声明性区域中。

using-declaration :
   using typenameopt 嵌套名称说明符 unqualified-id ;

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

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

不合格的名称查找i在其中sizeof(i)找到哪些?

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

或者它是否只找到struct i {};并且static int i = 1;哪些位于不同的名称空间中,因此程序格式错误?

还是我们有其他选择?

4

2 回答 2

1

N4527 [7.3.3p13]:

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

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
}

—结束示例]

请注意两个不同s 的using-declarationsx - 这与您的示例相同。


您的第一句话是指using-directives,而不是using-declarations

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

类名 (9.1) 或枚举名 (7.2) 可以被同一范围内声明的变量、数据成员、函数或枚举数的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称可见。

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

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


基本上,将using-declaration引入的名称视为某个实体的另一个名称,该实体也在其他地方命名(由using-declaration中的限定 ID嵌套名称说明符指定的位置)。这与using-directive的作用不同。我倾向于将using-directives视为“名称查找调整”。

于 2015-07-29T21:24:52.157 回答
1

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

如果名称查找在两个不同的命名空间中找到一个名称的声明,并且这些声明没有声明相同的实体并且没有声明函数,则该名称的使用是错误的。

但在示例中,我们有:

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) 可以被同一范围内声明的变量、数据成员、函数或枚举数的名称隐藏。如果一个类或枚举名称和一个变量、数据成员、函数或枚举器在同一范围内(以任何顺序)以相同名称声明,则无论变量、数据成员、函数或枚举器名称可见。

因此,如果两个is 在同一范围内,则该类是隐藏的(与using-declarations的顺序无关!),并指的是 的同义词。两个s 都在同一个命名空间 ( ) 中,这就是您的报价不适用的原因。这与您之前的问题不同,您之前使用的是using-directivessizeof(i)::iN::ii::

using namespace M;
using namespace N;

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

于 2015-07-29T21:42:45.217 回答