"::namespace::identifier" 和 "namespace::identifier" 之间有什么区别?

4
我在代码中看到了这两种方法。你能解释一下它们之间的区别吗?我认为这与C++的命名空间查找方式有关,你能提供一些相关信息或者好的文档链接吗?谢谢。

5
这就像是/usr/bin/rmusr/bin/rm之间的区别,或者是Windows\calc.exeC:\Windows\calc.exe之间的区别。 - Kerrek SB
这是真的吗?如果我声明了一个命名空间并使用标识符“std::cout”,它仍然可以工作 - 但我的命名空间中没有嵌套“std”命名空间。 - Dan Nestor
它意味着全局范围。请参考马克在此类似问题的答案:https://dev59.com/oXVD5IYBdhLWcg3wI3-L - Dave M
1
@DanNestor:嗯,就是这样,而且根目录始终在搜索路径中,如果你愿意的话 :-) - Kerrek SB
2个回答

12

示例:

#include <cstdio>

namespace x {
    const int i = 1;
}

namespace y {
    namespace x {
        const int i = 2;
    }

    void func()
    {
        std::printf("x::i = %d\n", x::i);
        std::printf("::x::i = %d\n", ::x::i);
    }
}

int main()
{
    y::func();
    return 0;
}

输出:

x::i = 2
::x::i = 1

解释:

  • 当你引用诸如 x::i 这样的标识符时,使用的定义是最“近”的 x::i。在 ::y::func 中,定义 ::y::x::i 比定义 ::x::i 更接近。相反地,没有这样的函数 ::y::std::printf,所以使用了 ::std::printf

  • 当你引用诸如 ::x::i 这样的标识符时,不存在任何可能的歧义:它查找名为 x 的顶层命名空间,然后找到其中一个 i

因此,使用开头的 :: 允许你拼写全局对象的完整名称,并且可以区分局部变量和全局变量。

示例2:

#include <cstdio>
const int x = 5;
int main()
{
    const int x = 7;
    std::printf("x = %d\n", x);
    std::printf("::x = %d\n", ::x);
    return 0;
}

输出:

x = 7
::x = 5

为什么在命名空间“y”内部,“std::printf”可以正常工作?没有嵌套在命名空间“y”内的“std”命名空间。您能否解释一下这一点? - Dan Nestor
1
@drandrestor:这就像变量作用域一样 - 如果编译器在当前级别找不到名称,它会“弹出”一级并在那里查找。在这种情况下,命名空间std不存在于y中,因此编译器会检查全局命名空间并在其中找到它。 - Ken Wayne VanderLinde
2
@SethCarnegie:Ken Wayne VanderLinde似乎已经掌握了这种特定的技艺(请参见他的金徽章)。 - Dietrich Epp
我接受了Ken的答案,因为他准确地解释了如果在当前作用域中找不到命名空间,则会搜索父级作用域。非常感谢Dietrich提供非常详细的答案。 - Dan Nestor

5

大部分时间来说,这并不重要。

在格式为::identifier1::identifier2的情况下,前面的冒号表示在全局范围内查找identifier1,然后在该范围内查找identifier2

在格式为identifier1::identifier2的情况下,我们会在当前范围内查找identifier1。如果没有找到,则会搜索父范围,直到找到为止。然后,在刚刚找到的任何范围内搜索identifier2

如果你已经处于全局范围内,那么这并不重要。但是,在工作中使用命名空间或嵌套其他命名空间或类的类时,情况就会发生改变。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接