C++:using声明和指令的顺序会影响选择吗?

3
以下是示例代码。
#include <iostream>
using namespace std;


namespace A {
    void f() { cout << "a" << endl; }
}
namespace B {
    void f() { cout << "b" << endl; }
}
namespace C {
    using namespace A;
    using namespace B;
    using A::f;
}
namespace D {
    using A::f;
    using namespace A;
    using namespace B;
}
int main()
{
    C::f();
    D::f();
}

在Visual Studio 2015中尝试时,这会打印两次“a”,这种行为是由标准定义的还是特定于实现的?

虽然这是一个完全有效的语言律师问题,但我希望你不要在创建真实世界的应用程序时遵循这种做法。 - R Sahu
@RSahu太晚了,我已经将一些类似的代码提交到某个仓库中。 - pasha
永远改善你的代码都不会太晚 :) - R Sahu
@pasha 运行...他们正在装弹...你仍然可以离开那里。 - UKMonkey
@UKMonkey ....是啊 <*紧张的笑*> - pasha
2个回答

4

这是由标准定义的(像这样的东西总是这样)。重要的是要认识到,您各种using namespace行对程序没有任何影响。

using namespace Foo 是一个“使用指令”,它会影响代码在该作用域内执行的名称查找。也就是说,如果您的namespace C {}块中的某个后续函数尝试查找名为foo的对象,则编译器将在AB中搜索以查找foo。相比之下,如果后面的代码引用了C::foo,那么它不会改变编译器查找的位置。单个块中两个连续的using namespace的顺序无关紧要,因为每个指令对块结束前都有效。

您能够在CD中找到f的原因是“使用声明”using A::f。使用声明与使用指令不同,它的效果是将名称注入到作用域中,以便其他代码可以将名称视为在该作用域内。


对于任何查看此答案的人,请查看idmean的答案,它更详细地涉及了同一主题。 - pasha

4
以下来自cppreference.com的两个段落将解释此行为:

使用指令[using namespace A;]不会向其所在的声明区域添加任何名称(与using声明[using A::f;]不同),因此不会防止声明相同的名称。

对于无限定查找,使用指令是可传递的:如果作用域包含一个指明命名空间名称的使用指令,该名称空间本身包含一些namespace-name-2的使用指令,则效果就像第二个命名空间中的使用指令出现在第一个命名空间中一样。这些传递性命名空间出现的顺序不会影响名称查找。

简单来说:using A::f;就好像在此命名空间中声明了该函数。using namespace A;只是使得类型名称查找表现得好像当前命名空间(CD)是A中的命名空间。
这类似于以下方式:
namespace A {
    void f() { cout << "a" << endl; }

    namespace B {
        void f() { cout << "b" << endl; }
    }
}

并且

namespace A {
    namespace B {
        void f() { cout << "b" << endl; }
    }

    void f() { cout << "a" << endl; }
}

等价。


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