【问题标题】:namespace composition and selection命名空间的组成和选择
【发布时间】:2018-07-18 08:30:14
【问题描述】:

读完C++ 编程语言第 4 版(第 14.4.4 节 - 合成和选择)我认为以下程序可以正确编译:

#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: 变量

baz: 1

当我尝试编译上面的代码时,我收到一条错误消息,指出对“var”的引用不明确。使用foo::var 消除了编译错误,但我想更好地理解这个问题。

我的代码有什么问题?

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

谢谢!

编辑

正如以下答案中所建议的,将 qux 的定义移动到命名空间 baz 内使其有效。因此,以下代码按预期编译

#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);
}

还有一件事我并不完全清楚。我认为添加using namespace baz 将使baz 中的所有内容在当前范围内也可用,而无需使用baz::。换句话说,我原以为“一切都在命名空间 baz 中有效”,在添加 using namespace baz 后,在当前范围内也是如此。

【问题讨论】:

  • 不要使用using namespace xxxx
  • 虽然我不同意@NathanOliver 的观点,但我 1) 被可能比我更好的程序员投票否决,并且 2) 我会从不使用命名空间组合可能必须像您尝试做的那样解决。 (即使它是可能的,它可能是,虽然我怀疑)
  • @zzxyz 我在使用using namespace xxxx 时遇到了一些错误/错误。一个非常不直观。在被烧了几次之后,我刚刚决定完全限定这些名字更安全。您可以为命名空间名称命名以减少输入。
  • @zzxyz: using std::string; using std::vector; (etc.) 使 STL 代码同样出色,并且不会导致您不知道的名称冲突。
  • @zzxyz:所以使用第二个。 using 不是邪恶的,除非它出现在全局范围内并且后面跟着 namespace

标签: c++ using using-directives using-declaration


【解决方案1】:
using foo::var;

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

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;

See it live

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

【讨论】:

    【解决方案2】:

    所以问题是当您使用可以来自两个命名空间的变量名时。当您在特定级别有多个候选人时,那就是模棱两可了。 你有foo::varbar::var,你得到 using namespace foo; using namespace bar;

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

    if (n == foo::var) 
    {
        std::cout << "baz: var " << std::endl;
    } 
    else if(n == bar::var) 
    {
        std::cout << "baz: " << n << std::endl;
    }
    

    【讨论】:

      【解决方案3】:
      // I thought that the following line would resolve the name clash
      using foo::var;   
      

      嗯,它确实解决了当前命名空间的名称冲突,即baz

      如果您将qux 移动到baz,它将更喜欢foo::var

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

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

      【讨论】:

        猜你喜欢
        • 2015-12-21
        • 2016-07-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-05-20
        • 2017-06-02
        • 1970-01-01
        相关资源
        最近更新 更多