C++ 在命名空间中使用声明的范围
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/6175705/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
scope of using declaration within a namespace
提问by Brett Ryland
Is it safe (and correct) in a C++ header file to use the using declaration within a namespace as follows:
在 C++ 头文件中使用命名空间中的 using 声明是否安全(和正确),如下所示:
#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
using boost::numeric::ublas::vector;
vector MyFunc(vector in);
}
I.e. is the "using boost::numeric::ublas::vector" properly contained within the MyNamespace block, or will this pollute the namespace of any file that includes this header?
即“使用 boost::numeric::ublas::vector”是否正确包含在 MyNamespace 块中,或者这是否会污染包含此标头的任何文件的命名空间?
采纳答案by ltjax
No, it is not safe - it won't pollute another namespace, but it is dangerous for other reasons:
不,它不安全——它不会污染另一个命名空间,但由于其他原因它是危险的:
A using
directive will import anything that is currently visibleby the name you specify into the namespace where you use it. While your using
will only be visible to users of MyNamespace
, other things from "outside" will be visible to your using
declaration.
一个using
指令将导入任何当前可见由你指定到您使用它的命名空间的名称。虽然您using
只会对 的用户可见MyNamespace
,但“外部”的其他内容将对您的using
声明可见。
So how is this dangerous when used in a header? Because it will import things that are visible at the point of the declaration, the exact behavior will depend on the order of headers you include before the declaration (There might be different things visible from boost::numeric::ublas::vector
). Since you cannot really control which headers are included before your header (nor should you be! headers should be self-sufficient!), this can lead to very strange problems where your function will find one thing in one compilation unit, and another in the next.
那么在标题中使用时这有什么危险呢?因为它将导入在声明点可见的内容,确切的行为将取决于您在声明之前包含的标题的顺序(从 中可能有不同的可见内容boost::numeric::ublas::vector
)。由于您无法真正控制在您的标头之前包含哪些标头(也不应该!标头应该自给自足!),这可能会导致非常奇怪的问题,您的函数将在一个编译单元中找到一个东西,而另一个在编译单元中下一个。
As a rule of thumb, using
declarations should only be used afterall includes in a .cpp file. There's also an item on this exact issue in the book "C++ Coding Standards" by Sutter and Alexandrescu (Item 59). Here's a quote: "But here's the common trap: Many people think that using declarations issued at namespace level (...) are safe. They are not. They are at least as dangerous, and in a subtler and more insidious way."
根据经验,using
只有在 .cpp 文件中包含所有内容之后才能使用声明。在 Sutter 和 Alexandrescu 合着的“C++ 编码标准”一书中(第 59 项),还有一个关于这个确切问题的条目。这是一个引述:“但这里有一个常见的陷阱:许多人认为 using 在命名空间级别 (...) 发布的声明是安全的。他们不是。它们至少同样危险,并且以更微妙和更阴险的方式。”
Even when it's unlikely that the name you are using
doesn't exist anywhere else (as is probably the case here), things can get ugly: In a header, all declarations should be fullyqualified. This is pain, but otherwise, strange things can happen.
即使您的名字不太可能using
在其他任何地方不存在(就像这里的情况一样),事情也会变得丑陋:在标题中,所有声明都应该是完全限定的。这是痛苦,但除此之外,可能会发生奇怪的事情。
Also see Migrating to Namespaces, Using-declarations and namespace aliasesand Namespace Namingfor examples and the problem described in-depth.
另请参阅迁移到命名空间、使用声明和命名空间别名以及命名空间命名以获取示例和深入描述的问题。
回答by Bj?rn Pollex
A using declaration is, as the name says, a declaration. All declarations are scoped to the enclosing block (7.2), in this case the namespace MyNamespace
. It will not be visible outside that namespace.
顾名思义,using 声明就是一个声明。所有声明的范围都在封闭块 (7.2) 内,在本例中为 namespace MyNamespace
。它在该命名空间之外不可见。
回答by B?ови?
It is safe, but it will pollute the MyNamespace namespace. So, any file that include that header will have functions/classes in the MyNamespace.
它是安全的,但它会污染 MyNamespace 命名空间。因此,任何包含该头文件的文件都将在 MyNamespace 中具有函数/类。
回答by Nils von Barth
To summarize, no, using-declarations in a header are not ok, even within a namespace, for 2 reasons. Further, using-declarations within a namespace in a non-header are error-prone or pointless (see end). Using-declarations in a header are not ok because:
总之,没有在头部使用,声明是不正常,即使在一个命名空间,原因有二。此外,非标头中命名空间内的 using 声明容易出错或毫无意义(见结尾)。在标头中使用声明是不行的,因为:
- They introduce a name into the namespace, which affects all filesthat include the header.
- They introduce only declarations for the name that have already been seen, which means that behavior depends on order of includes!
- 它们在命名空间中引入了一个名称,这会影响包含标题的所有文件。
- 它们只为已经看到的名称引入声明,这意味着行为取决于包含的顺序!
In your example, this means that:
在您的示例中,这意味着:
- Within
MyNamespace
,vector
now may resolve toboost::numeric::ublas::vector
, for any files that include this header: it "pollutes" theMyNamespace
namespace. - Which
boost::numeric::ublas::vector
declarations are imported depends on what declarations appear beforethis using-declaration, which depends on the order of includes in the file that includes this header, and all of itsincludes(properly, the order of declarations in the translation unit, after preprocessing).
- 在
MyNamespace
,vector
现在可以解析为boost::numeric::ublas::vector
, 对于包含此标头的任何文件:它“污染”了MyNamespace
命名空间。 - 其
boost::numeric::ublas::vector
声明是进口的依赖于出现什么样的声明之前,这个using声明,这取决于顺序包括包含这个头文件中,所有的公司包括(正确,声明的翻译单元的顺序,预处理后) .
Per your comment of May 30 '11 at 11:51you actually want behavior 1, but this doesn't work, due to problem 2. You can get the desired behavior by having a separate header that is included after all others (and fully qualifying the name in other headers). However, this is fragile and thus discouraged, preferably being reserved only when transitioning to namespaces:
根据您在 2011 年 5 月 30 日 11:51 的评论,您实际上想要行为 1,但由于问题 2,这不起作用。限定其他标题中的名称)。然而,这是脆弱的,因此不鼓励,最好只在转换到命名空间时保留:
//--- file myheader.hpp ---
#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
::boost::numeric::ublas::vector MyFunc(::boost::numeric::ublas::vector in);
}
//--- file myproject_last.hpp ---
namespace MyNamespace {
using ::boost::numeric::ublas::vector;
}
//--- file myproject.cpp ---
#include "myheader.hpp"
// ...other includes
#include "myproject_last.hpp"
See GotW #53: Migrating to Namespacesfor details, this workaround, and advice: "Namespace using declarations should never appear in header files."
有关详细信息、此解决方法和建议,请参阅GotW #53:迁移到命名空间:“使用声明的命名空间不应出现在头文件中。”
It is possible to avoid problem 1 by adding an unnamed namespace around the using-declaration (to prevent those names from being visible) and then another one outside the unnamed namespace (to make the desired name itselfvisible), but that still suffers from problem 2 and uglifies the header:
可以通过在 using 声明周围添加一个未命名的命名空间(以防止这些名称可见)然后在未命名的命名空间之外添加另一个命名空间(使所需的名称本身可见)来避免问题 1 ,但这仍然存在问题2 并丑化标题:
//--- file myheader.hpp ---
#include <boost/numeric/ublas/vector.hpp>
namespace MyNamespace {
namespace {
using ::boost::numeric::ublas::vector;
vector MyFunc(vector in);
}
using MyFunc; // MyNamespace::(unique)::MyFunc > MyNamespace::MyFunc
}
Due to these problems, you should only use using-declarations in non-header (.cc/.cpp) files: this doesn't affect other files, so problem 1 is avoided; and all headers have been included, so problem 2 is avoided. In this case it's a matter of taste whether you put them in a namespace or not, since they don't affect other files; it's safest to always use fully qualified names on in the using-declaration itself (absolute, starting with ::
).
由于这些问题,您应该只在非头文件(.cc/.cpp)中使用 using 声明:这不会影响其他文件,因此可以避免问题 1;并且已包含所有标题,因此避免了问题 2。在这种情况下,是否将它们放在命名空间中是一个品味问题,因为它们不会影响其他文件;在 using 声明本身中始终使用完全限定名称是最安全的(绝对的,以 开头::
)。
Simplest is to put all using-declarations at the top of the file, after the includes, but outside of any namespaces: this is safe, unambiguous, easy to read, and allows the names to be used throughout the file. Some common deviations:
最简单的是将所有 using 声明放在文件顶部,在包含之后,但在任何名称空间之外:这是安全的、明确的、易于阅读的,并且允许在整个文件中使用名称。一些常见的偏差:
- Using-declaration within a function (or struct or class or nested block): fine. This minimizes scope and is just a matter of taste: using-declaration is close to use (legibility win), but they are now scattered throughout the file (legibility loss).
Using-declaration with a relative name within a (named) namespace: error-prone. This is more concise and adds some clarity (related names used in the namespace to which they relate), but is potentially ambiguous (just like includes with relative paths), and is safer to avoid:
using ::foo::bar; namespace foo { ... } namespace foo { // Implicitly ::foo:bar, could be ::bar, or ::other::foo::bar. using bar; }
Using-declaration with an absolute name within a named namespace: pointless. This introduces the name only into the namespace, but you shouldn't care, since you shouldn't be including the .cc/.cpp file:
namespace foo { using ::bar; }
Using-declaration within an unnamed namespace: pointless, slightly dangerous. For example, if you have a function in an unnamed namespace, say an implementation detail, then you can have a using-declaration for its return type or param types. This introduces the name into just that namespace (so can't be referenced from other files), but again, you shouldn't care, since you shouldn't be including the .cc/.cpp file (unnamed namespaces are especially for avoid name clashes at link time, which isn't applicable here: it's just a compile-time alias). Worse, it introduces ambiguity if that name already does exist!
- 在函数(或结构、类或嵌套块)中使用声明:很好。这将范围最小化,只是一个品味问题:使用声明接近使用(易读性获胜),但它们现在分散在整个文件中(易读性丢失)。
在(命名)命名空间中使用具有相对名称的声明:容易出错。这更简洁并增加了一些清晰度(在它们相关的命名空间中使用的相关名称),但可能有歧义(就像包含相对路径一样),并且更安全地避免:
using ::foo::bar; namespace foo { ... } namespace foo { // Implicitly ::foo:bar, could be ::bar, or ::other::foo::bar. using bar; }
在命名空间中使用绝对名称声明:pointless。这仅将名称引入命名空间,但您不必在意,因为您不应该包含 .cc/.cpp 文件:
namespace foo { using ::bar; }
在未命名的命名空间中使用声明:毫无意义,有点危险。例如,如果您在未命名的命名空间中有一个函数,比如一个实现细节,那么您可以为其返回类型或参数类型使用 using 声明。这将名称引入到该命名空间中(因此不能从其他文件中引用),但同样,您不应该在意,因为您不应该包含 .cc/.cpp 文件(未命名的命名空间特别是为了避免链接时名称冲突,这在此处不适用:它只是编译时别名)。更糟糕的是,如果该名称已经存在,则会引入歧义!
回答by Puppy
It will not pollute any other namespaces, but it certainly will pollute the MyNamespace namespace.
它不会污染任何其他命名空间,但肯定会污染 MyNamespace 命名空间。