【问题标题】:How does unqualified name lookup work when using using-declarations?使用 using-declarations 时,非限定名称查找如何工作?
【发布时间】:2015-10-21 01:37:21
【问题描述】:

根据 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 typenameoptnested-name-specifier unqualified-id ;

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

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

isizeof(i) 中的非限定名称查找会找到哪些?

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

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

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

【问题讨论】:

  • 我确定我最近看到了一个关于此的问题,得出的结论是存在错误。你搜索过吗?
  • 问题不完全相同。这是一个后续问题。
  • @LightnessRacesinOrbit 哦,好的。我没有想到。感谢您指出。

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


【解决方案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的顺序!),并且@987654328 @ 指的是::i,它是N::i 的同义词。 is 都在 same 命名空间 (::) 中,这就是您的报价不适用的原因。这与您的 earlier question 不同,您使用的是 using-directives

using namespace M;
using namespace N;

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

【讨论】:

    【解决方案2】:

    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
    }
    

    ——结束示例 ]

    注意两个不同 xs 的 using-declarations - 这与您的示例相同。


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

    sizeof(i) 中对i 进行非限定名称查找会在全局命名空间中找到is。由于它们是同一范围内的声明,因此根据 [3.3.10p2](以下引用),变量 i 隐藏了 struct

    类名 (9.1) 或枚举名 (7.2) 可以通过名称隐藏 中声明的变量、数据成员、函数或枚举数 范围相同。如果一个类或枚举名称和一个变量,数据 成员、函数或枚举器在同一范围内声明(在任何 order) 同名,隐藏类名或枚举名 变量、数据成员、函数或枚举器名称在哪里 可见。

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

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


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

    【讨论】:

    • 术语 using-declarationusing-directive 的接近程度无助于理解我敢肯定... :)跨度>
    • @Barry 非常正确。而且,在经典的 C++ 风格中,它们都根据上下文做不止一件事。更不用说 using 关键字本身,它的重载更加严重。
    猜你喜欢
    • 2015-10-20
    • 2021-02-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-10-16
    • 2014-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多