命名空间的组成和选择

namespace composition and selection

提问人:carlo 提问时间:2/8/2018 最后编辑:Communitycarlo 更新时间:2/8/2018 访问量:334

问:

阅读《C++ 编程语言第 4 版》(第 14.4.4 节 - Composition and Selection)我以为以下程序可以正确编译:

#include <iostream>

namespace foo {
    int var = 0;
    // more declarations
}

namespace bar {
    int var = 1;
    // more declarations
}

namespace baz {
    // composition of namespaces foo and bar
    using namespace foo;
    using namespace bar;
    // I thought that the following line would resolve the name clash
    using foo::var;   
}

using namespace baz;

void qux(int n) {
    if (n == var) {
        std::cout << "baz: var " << std::endl;
    } else {
        std::cout << "baz: " << n << std::endl;
    }
}

int main() {
    qux(0);
    qux(1);
}

预期输出应为

BAZ: var

巴兹:1

当我尝试编译上面的代码时,我收到一个错误,说对“var”的引用是模棱两可的。使用消除了编译错误,但我想更好地理解这个问题。foo::var

我的代码有什么问题?

如何以命名空间 baz 包含的方式解决名称冲突?foo::var

谢谢!

编辑

如以下答案所示,在命名空间内移动 的定义可使其有效。因此,以下代码将按预期方式进行编译quxbaz

#include <iostream>

namespace foo {
    int end = 0;
}

namespace bar {
    int end = 1;
}

namespace baz {
    using namespace foo;
    using namespace bar;
    using foo::end;
    void qux(int n) {
        if (n == end) {
            std::cout << "baz: end " << std::endl;
        } else {
            std::cout << "baz: " << n << std::endl;
        }
    }
}

int main() {
    baz::qux(baz::end);
    baz::qux(1);
}

还有一件事我并不完全清楚。我认为添加将使所有内容在当前范围内也可用,而无需使用 .换句话说,我本来以为,由于“一切都在命名空间 baz 中工作”,因此在添加 .using namespace bazbazbaz::using namespace baz

使用 using 指令 using-declaration 的 C++

评论

3赞 NathanOliver 2/8/2018
不要使用using namespace xxxx
1赞 zzxyz 2/8/2018
虽然我不同意@NathanOliver,但我 1) 被可能比我更好的程序员投票否决,以及 2) 我永远不会使用可能必须像您尝试的那样解决的命名空间组合。 (即使这是可能的,它可能是,尽管我怀疑)
1赞 NathanOliver 2/8/2018
@zzxyz 我在使用 .一个是非常不直观的。在被烧了几次之后,我决定完全限定这些名字会更安全。您可以为命名空间名称添加别名,以减少键入。using namespace xxxx
1赞 Ben Voigt 2/8/2018
@zzxyz:(等)使 STL 代码同样漂亮,并且不会导致您不知道的名称冲突。using std::string; using std::vector;
1赞 Ben Voigt 2/8/2018
@zzxyz:所以使用第二个。 不是邪恶的,除非它出现在全局范围内,后面跟着 。usingnamespace

答:

2赞 Arnav Borborah 2/8/2018 #1
using foo::var;

上面的那一行基本上什么也没做,只是让你的函数调用更加模棱两可。第一个使命名空间中的任何内容都可以使用 (So )。下一行对命名空间执行相同的操作。最后一行,如上所示,告诉编译器专门删除仅在 baz 内部的命名空间限定符。因此,在 if 语句中,编译器有 3 个候选选项可供选择,并且不能选择任何候选选项。GCC 7.2 给出的确切错误是:using namespace foofoofoo::varbarfoo::var

prog.cc:在函数“void qux(int)”中:

prog.cc:24:14:错误:对“var”的引用不明确 if (n == var) {

prog.cc:4:9:注意:候选者是:int foo::var int var = 0;

prog.cc:9:9:注意:int bar::var int var = 1;

prog.cc:4:9:注意:int foo::var int var = 0;

现场观看

为了避免这种歧义,最好避免使用此类语句,而是完全限定所有名称。using namespace a;

0赞 Michał Kalinowski 2/8/2018 #2

因此,问题在于当您使用可以从两个命名空间中获取的变量名称时。当你在特定级别有多个候选人时,这就是一个模棱两可的地方。 你有 和 ,你使foo::varbar::var using namespace foo; using namespace bar;

现在,当编译器看到 var 时,他不知道你想使用哪个。 如果你真的想使用它,那么你需要为这些变量做一个例外,并说出你的意思:varusing namespace

if (n == foo::var) 
{
    std::cout << "baz: var " << std::endl;
} 
else if(n == bar::var) 
{
    std::cout << "baz: " << n << std::endl;
}
2赞 Ben Voigt 2/8/2018 #3
// I thought that the following line would resolve the name clash
using foo::var;   

好吧,它确实解决了当前命名空间的名称冲突,这是 baz

如果你搬进去,它会更喜欢 。quxbazfoo::var

但是对于(在任何命名空间之外),没有理由更喜欢(别名)而不是 或,因为它们都在当前的命名空间搜索路径中。::quxbaz::varfoo::varbar::varfoo::var

尽管只在全球范围内看到。using namespace baz;