命名空间引用和包含的顺序会影响编译结果

时间:2013-11-29 15:29:51

标签: c++ namespaces include

我一直认为我们应该在包含后使用命名空间,例如,我们应该使用:

#include <vector>
using std::vector; 

而不是

using std::vector;
#include <vector>

但我发现第二个是好的,让我困惑的是它们的不同排序会导致不同的结果。参见下面的简单示例:这里有两个头文件和一个c ++文件。

// test1.h
#include <vector>

using std::vector;
#include "test2.h"

// test2.h
vector<int> v;

// test.cpp
#include "test1.h"

int main()
{
    return 0;
}

尽管test2.h不包含vector,但它编译好以上所有。 奇怪的是当我交换使用std :: vector的顺序时;和#include一样,会发生这样的编译错误:

错误C2143:语法错误:缺少';'在'&lt;'

之前

错误C2501:'vector':缺少存储类或类型说明符

错误C2143:语法错误:缺少';'在'&lt;'

之前

错误C2874:using-declaration导致'vector'的多重声明

我不了解内部,命名空间的顺序和包含真的很重要吗?为什么这样呢?

4 个答案:

答案 0 :(得分:1)

将名称转储到全局命名空间通常是一个坏主意,它们可能会与用户声明的名称冲突 - 特别是在标题中,您强制污染该标题的所有用户。话虽如此:

  

我发现第二个是好的

仅因为某些内容已包含<vector>或已声明为std::vector。正如您在后面的示例中所看到的,否则会出现错误。

  

我不了解内部,命名空间的顺序和包含真的很重要吗?

是的,using声明只能引用已声明的名称。

  

为什么这样呢?

因为这就是语言的运作方式。您通常不能使用尚未声明的名称。

答案 1 :(得分:1)

// test2.h
vector<int> v;

头文件应该是自给自足的。像这样编写test2.h要求用户同时#include <vector>并添加using声明,以便可以在不限定其名称的情况下编写vector。这意味着标题不是自给自足的,因为你不能简单地#include它而不先做其他事情。

您也不应该在头文件中定义变量。在头文件中,您应该只声​​明extern个变量。

#ifndef TEST2_H
#define TEST2_H

#include <vector>

extern std::vector<int> v;

#endif

这里我还添加了#ifndef / #define guard,因此可以多次包含头文件而不会出错。我还使用了完全限定的std::vector而没有使用using:将using声明放在头文件中是合法的,但不好的做法。

答案 2 :(得分:1)

此:

using std::vector;
#include <vector>

确定,除非该文件已包含 <vector>

重要的是,#include执行文字替换。它就像在#include指令上粘贴包含文件的内容一样。头文件不是自己编译的,只是形成正在编译的源文件的文本部分。

因此,您的示例有效,因为在包含test2.h时,正在编译的源文件(test.cpp)已包含来自#include <vector>的{​​{1}}和using std::vector; 。这就是为什么当你交换时它会中断的原因 - test1.htest2.h声明之前被包含在内,因此在使用它时不存在不合格的using

答案 3 :(得分:0)

预处理程序指令#include是文本替换操作。它将读取包含的文件并将#include替换为其内容。如果您根据操作的内容进行考虑,答案应该是明确的。

预处理后main.cpp变为:

// start test1.h
#include <vector>

using std::vector;
// start test2.h
vector<int> v;
// end test2.h
// end test1.h

int main()
{
    return 0;
}

如果您更改using指令的顺序以包含标题,您将获得(删除评论):

#include <vector>
vector<int> v;
using std::vector;
//...

v的定义时,尚未看到using声明,编译器不知道vector的含义,因此也不知道错误消息。

现在回到最初的假设:

using std::vector;
#include <vector>
  

但我发现第二个是好的

不,不行。根据您拥有的其他包含内容,它可能会编译,但在编译器看到声明的元素之前,您无法提供using声明。如果上面的两行编译,则意味着在第一行之前的某处,包含的扩展已经将std::vector的声明带入此翻译单元。尝试在单个.cpp中单独编译它,你会看到一些错误。

相关问题