命名空间组成和选择

时间:2018-02-07 22:13:50

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

阅读 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:var

     

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后的当前范围内也是如此。

3 个答案:

答案 0 :(得分:2)

using foo::var;

除了使你的函数调用更加模糊之外,上面的行基本上什么都不做。第一个using namespace foo在名称空间foo中生成任何内容,而不foo::(所以var)。下一行对命名空间bar执行相同的操作。最后一行(如上所示)告诉编译器仅在baz 中专门删除foo::var 的命名空间限定符。因此,在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;的语句,而是完全限定所有名称。

答案 1 :(得分:2)

// I thought that the following line would resolve the name clash
using foo::var;   

好吧,它确实解析了当前命名空间的名称clash ,即baz

如果您将qux移至baz,则会更喜欢foo::var

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

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

答案 2 :(得分:0)

问题是当你使用可以来自两个命名空间的变量名时。如果您在特定级别有多个候选人,那么这是一个含糊不清的问题。 您有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;
}