C++命名空间中的名称解析规则是什么?

What are the name resolution rules in C++ namespaces?

如何在 C++ 命名空间中解析名称?

我对以多种不同方式提供名称的情况特别感兴趣,例如通过父命名空间和 using namespace

拿这段代码来说:

namespace ns1 {
    static auto str = "ns1::str";
}
namespace ns2 {
    static auto str = "ns2::str";
    namespace sub {
        using namespace ns1;
        auto f() { return str; }
    }
}

使用我的编译器,ns2::sub::f() returns "ns2::str"。我预计它会 return "ns1::str",因为 using namespace ns1 出现在 ns2::sub.

现在这首曲子:

static auto str = "str";
namespace ns1 {
    static auto str = "ns1::str";
}
namespace ns2 {
    using namespace ns1;
    auto f() { return str; }
}

我预计它会像之前的案例那样运行。相反,它不编译:

error: reference to ‘str’ is ambiguous

这背后的逻辑是什么?

使用指令要牢记以下规则

[namespace.udir]

2 A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup ([basic.lookup.unqual]), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace. [ Note: In this context, “contains” means “contains directly or indirectly”. — end note ]

3 A using-directive does not add any members to the declarative region in which it appears.

第 3 段确保我们在尝试 名称查找之前不会收到错误。它不添加声明,只要 str 不被非限定名称查找查找,我们就不会发生冲突。而第 2 段告诉我们名称的逻辑布局方式。我们可以将其应用于您的两个示例。

  1. 包含 using namespace ns1; 和命名空间 ns1 本身的最近的封闭命名空间是全局命名空间。所以名称 ns1::str 的行为就好像我们写了

    static auto str = "ns1::str";
    namespace ns2 {
       static auto str = "ns2::str";
        namespace sub {
            auto f() { return str; }
        }
    }
    

    因此,名称查找只会找到 ns2::str,因为它会隐藏命名空间中的任何 str 和封闭的命名空间(这是上面代码中的“假设”情况)。

  2. 同样,最近的封闭命名空间是全局命名空间。但是这一次,我们得到的布局是不同的

    static auto str = "str"; // This is the one declared
    static auto str = "ns1::str"; // This is the one "as-if" made available
    
    namespace ns2 {
        auto f() { return str; }
    }
    

    显然,上面的“等效”代码片段无效,声明会相互冲突。但它是冲突根源的例证。来自该范围的名称存在冲突。所以不合格的名称查找失败。

在没有使用指令的情况下,非限定名称查找的行为相当直观。范围从内到外查找,直到找到名称声明。