using 声明的一致使用有多重要?
我对 using 声明的使用所做的大部分研究,包括阅读各种风格指南的相关部分,都表明是否在 C++ 源文件中使用 using 声明,只要它们出现在所有 #include 之后,就是一个问题。决定权留给编码人员。即使是我读过的风格指南,为了保持一致性,通常会针对此类常见争议的一方或另一方,在这方面也相当灵活。
我的问题是,考虑到这种高度的灵活性,使用一致的风格有多重要?例如,假设作者写了类似的内容
using std::vector;
vector<T> v;
std::cout << v[0] << std::endl;
,“在 std::vector 但不是 std::cout 或 std::endl 上使用的不一致应用通常被认为是可以接受的,还是会被认为是不守纪律的?”
Most of the research I've done on the use of using declarations, including reading relevant sections of various style guides, indicates that whether or not to use using declarations in C++ source files, as long as they appear after all #includes, is a decision left to the coder. Even the style guides I read, which usually come down on one side or the other of such common disputes for the sake of consistency, are fairly flexible in this regard.
My question is, given this high degree of flexibility, how important is it to use a consistent style? For example, suppose an author wrote something like
using std::vector;
vector<T> v;
std::cout << v[0] << std::endl;
Is the inconsistent application of using on std::vector but not std::cout or std::endl generally considered acceptable, or would it be considered undisciplined?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
我认为
using
的全部意义在于,您在名称之间使用不一致。在某些块中经常需要的名称可以使用 using 声明在本地声明,而其他块则不需要。我不认为这有什么问题。声明一个名称具有命名空间范围总是很难接受。我认为,如果清楚地知道该名称属于特定名称空间,那么就不会发生将其与其他名称空间混淆的情况,如果它使您的代码更具可读性,那么放置一个 using 声明不会有什么坏处。
I think the whole point of
using
is that you use it inconsistently among names. Names you need very frequently in some block can be declared locally with a using declaration, while others are not. I don't see a problem with that.Declaring a name to have namespace scope is always much harder to take. I think if the name clearly is known to belong to a particular namespace so that confusing it with other namespaces won't occur, It won't hurt to put a using declaration if it makes your code more readable.
我现在是明确声明名称空间的强烈支持者(即不“使用”)
的,> 100kloc 项目中)
大多数人的名称空间历史都是这样的(在不平凡 风格1
哎哟->样式2
好的,已经够了 ->款式3
I am now a strong proponent for explicitly stating the namespace (ie no 'using')
Most peoples namespace history goes like this (in non trivial, >100kloc projects)
Innocence -> style 1
Ouch -> style 2
OK, enough already -> style 3
假设您在任何地方都没有说
using namespace std;
,我认为大多数开发人员并不关心其他人的代码中的这种或那种方式。唯一可能困扰他们的是 std:: 限定符的过度使用——也就是说,如果你在函数中说“std::vector”20 次,也许是时候“using std::vector”了。否则,没有人应该关心。有时,在我自己的代码中,我会专门使用“std::”限定符来指示这是我唯一使用该标识符的地方。
Assuming you don't say
using namespace std;
anywhere, I don't think most developers care one way or another in other people's code. The only thing that might bother them is the overuse of the std:: qualifier --- that is if you're saying "std::vector" 20 times in the function, maybe it's time for a "using std::vector". Otherwise, no one should care.Sometimes, in my own code, I'll use the "std::" qualifier specifically to indicate that this is the only place that I'm using that identifer.
我尝试不使用
using
(没有双关语意图)。为了节省打字,我喜欢做 typedef,例如:
I try for not using
using
(no pun intended).For saving typing, I like to do typedefs, e.g.:
这与其说是一个答案,不如说是与其他一些答案的对立,这些答案主张始终明确地将命名空间作为名称的一部分。有时,这是一个糟糕的主意。在某些情况下,您希望使用专门针对当前类型的名称(如果存在),但否则使用标准提供的替代名称。
作为一个典型的例子,让我们考虑一个排序函数。如果您要对一些 T 类型的对象进行排序,您最终将交换项目。您希望使用特殊的
swap(T &, T&)
(如果存在),但templatestd::swap 否则。
如果您尝试显式指定要使用的交换的完整名称,则必须指定其中之一 - 要么指定专用版本,然后在未定义其自己的类型上实例化排序swap 将失败,否则您指定 std::swap,并忽略专门为您要排序的类型提供的任何交换。
using
提供了一种摆脱这种困境的方法:现在,如果 T 所在的命名空间包含
swap(T &, T&)
,那么它将是通过参数相关查找找到,并在上面使用。如果它不存在,则将找到(并使用)std::swap,因为 using namespace std; 也使其可见。顺便说一句,我认为只要稍加修改,
using namespace x;
就可以变得几乎完全无害。就目前而言,它将该命名空间中的名称引入到当前范围中。如果其中之一恰好与当前作用域中存在的名称相同,就会发生冲突。当然,问题是我们可能不知道名称空间包含的所有内容,因此几乎总是至少存在一些潜在的冲突。修改将使用
using namespace x;
视为它创建了一个围绕当前作用域的作用域,并将该命名空间中的名称引入到该周围作用域中。如果其中之一恰好与当前作用域中引入的名称相同,则不会发生冲突 - 就像任何其他块作用域一样,当前作用域中的名称将隐藏周围作用域中的相同名称。我还没有详细考虑这个问题,所以毫无疑问会有一些极端情况需要更多的关注来解决,但我认为总体思路可能会让很多事情变得更简单。
This is less an answer than a counterpoint to a few other answers that have advocated always explicitly including the namespace as part of the name. At times, this is a poor idea. In some cases, you want to use a name that's been specialized for the type at hand if it exists, but use a standard-provided alternative otherwise.
As a typical example, let's consider a sort function. If you're sorting some objects of type T, you're going to end up swapping items. You want to use a special
swap(T &, T&)
if it exists, buttemplate <class T> std::swap
otherwise.If you try to specify the full name of the swap you're going to use explicitly, you have to specify one or the other -- either you specify a specialized version, and instantiating your sort over a type that doesn't define it's own swap will fail, or else you specify
std::swap
, and ignore any swap that's been provided specifically for the type you're sorting.using
provides a way out of this dilemma though:Now, if the namespace in which T is found contains a
swap(T &, T&)
, it'll be found via argument dependent lookup, and used above. If it doesn't exist, thenstd::swap
will be found (and used) because theusing namespace std;
made it visible as well.As an aside, I think with one minor modification,
using namespace x;
could be made almost entirely innocuous. As it stands right now, it introduces the names from that namespace into the current scope. If one of those happens to be the same as a name that exists in the current scope, we get a conflict. The problem, of course, is that we may not know everything that namespace contains, so there's almost always at least some potential for a conflict.The modification would be to treat
using namespace x;
as if it created a scope surrounding the current scope, and introduced the names from that namespace into that surrounding scope. If one of those happened to be the same as a name introduced in the current scope, there would be no conflict though -- just like any other block scoping, the name in the current scope would hide the same name from the surrounding scope.I haven't thought this through in a lot of detail, so there would undoubtedly be some corner cases that would require more care to solve, but I think the general idea would probably make a lot of things quite a bit simpler anyway.