C ++标头中的“使用”指令

时间:2019-02-23 23:26:04

标签: c++

我对Koenig和Moo的 Accelerated C ++ 一书中的以下句子感到困惑:

// median.h
#include <vector>
double median(std::vector<double>);
  

在此示例中,我们使用std::vector的限定名称,因为   我们无法知道函数用户希望如何引用   到std::vector。我们代码的用户可能不需要   using-vector的声明。如果我们在标头中写一个   包含头文件的所有程序都将获得using std::vector   声明,无论他们是否想要它。头文件应该   使用标准名称而不是using-声明。

我不认为我理解这段话。如果我们在标头中有一个using std::vector声明,并且包括标头的整个程序都得到了相同的声明,那么仅当用户重新定义vector类时,这才可能成为问题,不是吗?但是我们的median函数仍然需要标准库中的vector,因此,如果用户想在新定义的median上使用vector,则会产生错误在编译时。

2 个答案:

答案 0 :(得分:6)

如果头文件是:

#include <vector>
using std::vector;
double median(vector<double>);

这将告诉所有包含median.h的编译单元(例如cpp文件)函数median接受std::vector,同时使std::vector可以通过无限定的查询访问vector在这些编译单元中。

如果编译单元可以访问另一个不合格的vector,则将发生名称冲突和构建错误。函数median永远不会收到不是std::vector的类型,即使该类型的名称也是vector

避免在头文件中声明using是个好主意,因为这是造成名称冲突的原因。

答案 1 :(得分:4)

要理解这些单词,有必要了解像using这样的using namespace std指令的作用。

默认情况下,当编译器看到vector之类的名称时,它会在当前上下文中查找vector(即,在您的示例中,它在“全局名称空间”中,或者等效地在{ {1}})。如果在该搜索中未找到候选匹配项(例如,名为::的匹配项),则会发出诊断信息,并停止编译。

vector使编译器在命名空间using namespace std中查找匹配的名称。如果找到明确的匹配项,则使用该名称。

如果存在另一个std指令(例如using),则会出现问题。例如;

using namespace foo

现在考虑如果 using namespace std; #include "foo.h" using namespace foo; #include "median.h" 在命名空间foo.h中指定一个模板化名称为vector的东西会发生什么。假设foo

median.h

由于有两个double median(vector<double>); 指令,因此编译器会在usingstd中查找名称foo。如果它在两个名称空间中都找到一个匹配项,则它具有两个候选匹配名称vectorfoo::vector

如果这两个名称都与std::vector完全相同,则由于含糊不清,因此该代码具有可诊断的错误。编译将失败。没有规则使编译器认为名称空间vector中的匹配比名称空间std中的匹配要好,反之亦然。

下一个问题是无法撤消foo指令的影响(例如,与其他using指令或声明一起使用)。在这种情况下编译代码的唯一方法是将using的声明更改为

median()

Koenig和Moo并没有从头开始,而是从一开始就提倡使用全名double median(std::vector<double>); ,而不是在标头中使用std::vector<double>指令。这样做可以使使用头文件的其他程序员在愿意的情况下使用using指令或声明,但并不要求这样做。

注意:以上内容过于简化。有很多详细的规则可以控制编译器如何查找候选名称,然后确定它们的匹配程度。