使用名称空间行为的基本原理 [英] Rationale behind using namespace behavior
问题描述
引用标准:
using指令指定所提名名称空间中的名称 可以在使用指令出现在以下位置的范围内使用 使用指令.在不合格的名称查找(3.4.1)期间,名称 好像它们是在最近的封闭命名空间中声明的一样 其中包含using指令和指定的名称空间.
A using-directive specifies that the names in the nominated namespace can be used in the scope in which the using-directive appears after the using-directive. During unqualified name lookup (3.4.1), the names appear as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace.
看下面的代码:
namespace A {
int fn() { return 1; }
}
namespace Inner {
int fn() { return 2; }
namespace B {
using namespace A;
int z = fn();
}
}
在这里,在我知道命名空间的确切规则之前,我曾希望在编写using namespace A
时将z
初始化为1,因此期望使用A::fn()
.但是不是这种情况,由于我引用的规则,z
将被初始化为2,因为Inner::fn()
被调用.
Here, before I knew the exact rules of namespaces, I had expected that z
will be initialized to 1, as I written using namespace A
, so expected that A::fn()
will be used. But it is not the case, z
will be initialized to 2, as Inner::fn()
is called because of the rule I quoted.
此行为背后的原理是什么:就像在包含使用指令和指定名称空间的最近的封闭名称空间中声明它们一样?"
What is the rationale behind this behavior: "as if they were declared in the nearest enclosing namespace which contains both the using-directive and the nominated namespace"?
如果using namespace
可以为该命名空间中的所有内容使用声明进行应用,那么会有什么弊端?
What would be the cons, if using namespace
worked as applying using declarations for everything in that namespace?
注意:这是促使我提出此问题的相关问题.
Note: this is the related issue that motivated me to ask this question.
推荐答案
名称空间系统的理想属性是我所说的增量API兼容性.也就是说,如果我将符号添加到命名空间,则任何以前运行的程序都应继续工作并表示相同的意思.
A desirable property of a namespace system is that of what I call incremental API compatibility. That is, if I add a symbol to a namespace, then any previously working program should keep working and mean the same thing.
现在,带有重载的普通C ++与增量API不兼容:
Now, plain C++ with overloads is not incrementally API compatible:
int foo(long x) { return 1; }
int main()
{
foo(0);
}
现在,我添加了重载int foo(int x) { return 2; }
,程序默默地更改了含义.
Now I add the overload int foo(int x) { return 2; }
and the program silently changes meaning.
无论如何,当C ++人员设计namespace
系统时,他们希望在增加外部API时,以前的工作代码不应更改选择符号的名称空间.在您的示例中,先前的工作代码将类似于:
Anyway, when C++ people designed the namespace
system they wanted that when incrementing an external API, previously working code should not change the namespace from where the symbol is chosen. From your example, the previous working code would be something like:
namespace A {
//no fn here, yet
}
namespace Inner {
int fn() { return 2; }
namespace B {
using namespace A;
int z = fn();
}
}
并且z
易于初始化为2
.现在,使用名为fn
的符号扩展名称空间A
不会更改该工作代码的含义.
And z
is easily initialized to 2
. Now augmenting namespace A
with a symbol named fn
will not change the meaning of that working code.
相反的情况并不适用:
namespace A {
int fn() { return 1; }
}
namespace Inner {
// no fn here
namespace B {
using namespace A;
int z = fn();
}
}
此处z
初始化为1
.当然,如果将fn
添加到Inner
,它将改变程序的含义,但是Inner
不是外部API:实际上,当最初编写Inner
时,A::fn
已经存在(它已经存在了)被召唤!),所以没有理由不意识到冲突.
Here z
is initialized to 1
. Of course, if I add fn
to Inner
it will change the meaning of the program, but Inner
is not an external API: actually, when Inner
was written initially, A::fn
did already exist (it was being called!), so there is no excuse for being unaware of the clash.
想象一下这个C ++ 98程序:
Imagine this C++98 program:
#include <iostream>
namespace A {
int move = 0;
void foo()
{
using namespace std;
cout << move << endl;
return 0;
}
}
int main()
{
A::foo();
return 0;
}
现在,如果我使用C ++ 11进行编译,则由于此using
规则,一切都可以正常工作.如果using namespace std
可以为该命名空间中的所有内容使用声明进行应用,则该程序将尝试打印功能std::move
而不是A::move
.
Now, if I compile this with C++11, everything works fine thanks to this using
rule. If using namespace std
worked as applying using declarations for everything in that namespace, then this program would try to print function std::move
instead of A::move
.
这篇关于使用名称空间行为的基本原理的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!