将C / C ++标准库拉入项目命名空间,好主意?

时间:2011-05-15 05:06:26

标签: c++ namespaces port

我正在移植一些开源代码,以便它可以构建在另一个c ++编译器上。似乎不断出现的困难和主题之一是编译器提供的标准库的实现差异。

例如,我正在编译的其中一个源文件包含<sys/types.h>。但是,它给了我以下错误:

Error E2316 g:\Borland\BCC593\Include\sys/types.h 45: 'time_t' is not a member of 'std'
Error E2272 g:\Borland\BCC593\Include\sys/types.h 45: Identifier expected

在查看了根本原因之后,我发现该项目的主要包含标题之一包括<sys/types.h>这种模式:

project_source1.cpp:

#include "../TargetPlatform.h"
#include "project_config.h"
#include <windows.h>

namespace project_namespace {
#include "project_component/all.h"
// more project includes down here
// ...
}

project_component / all.h:

#ifndef INCLUDE_GUARDS
#define INCLUDE_GUARDS

#include <sys/types.h>
#include "project_header1.h"
#include "project_header2.h"
// and other headers etc..
// followed with class definitions and what not.

#endif

这一切都很好,除了一个问题,<sys/types.h>实现了类似于我正在移植到的编译器:

<sys/types.h>修剪了本质:

namespace std {

typedef long time_t;
typedef short dev_t;
typedef short ino_t;
typedef short mode_t;
typedef short nlink_t;
typedef int   uid_t;
typedef int   gid_t;
typedef long  off_t;

} // std

using std::time_t;
using std::dev_t;
using std::ino_t;
using std::mode_t;
using std::nlink_t;
using std::uid_t;
using std::gid_t;
using std::off_t;

这就是我看到的编译错误的原因。因为项目在里面包含<sys/types.h> 自己的命名空间,所以像time_t,off_t,dev_t等这样的东西会被放入范围project_namespace::std::,这显然不是预期的。

处理此问题的最佳方法是什么?请记住,可能会以类似的方式定义其他标准库标头,而不仅仅是sys/types.h。是否存在与此问题相关或半相关的C ++习语(或者由于实现方式的原因,甚至可能与之相矛盾)?如果是这样,怎么能和解呢?

由于

2 个答案:

答案 0 :(得分:7)

这是一个坏主意。不要这样做。将名称空间声明放在每个头文件中。在命名空间的范围内永远不要有#include指令。

永远不是一个强有力的词,并且在极少数情况下您可能想要这样做。如果您#include的文件也有#include指令,那么您几乎肯定不希望这样做,甚至比他们没有这样做更多。

如果您需要能够轻松地重命名命名空间或使用相同的标头根据上下文在几个不同的命名空间中声明相同的符号,请使用预处理器来更改命名空间名称。这样做非常难看,但比你现在做的要好得多。

作为快速而肮脏的解决方案,您可以做的一件事是#include <sys/types.h>以及在命名空间声明之前包含的任何其他系统头。这将导致系统头文件中的双包含保护启动并避免在命名空间内声明内容。

答案 1 :(得分:1)

我想说你需要更改有问题的代码,以便不再在project_namespace中定义标准类型。

在我看来,你有两个主要问题:[1]你在project_all.h中有一个包罗万象的标题,而在#include内有namespace project_namespace d。我先说说后者。如果你的项目有想要放在自己的命名空间中的东西,那很好,但应该按如下方式完成:

// Foo.h
// includes go here
namespace project_namespace {
    class Foo { ... }
}
// Foo.cpp
// includes go here
namespace project_namespace {
    // Foo implementation goes here
}

...换句话说,你的类的头文件和实现文件需要说明类所属的命名空间,“自命名空间”。您的所有#include都在namespace之外,因为每个类的头文件都声明了该类所属的命名空间。这是标准库使用的约定。

现在,如果你仍想使用project_all.h,你可以这样做。没有命名空间 - 因为每个头文件都会将其声明放在它想要(或不是)的命名空间中。

但最好放弃project_all.h;相反,#include单独的头文件,并使依赖显式。如果响应是“头文件太多”,那么这可能是组件之间高度耦合的标志。

我意识到这可能不是你想要的答案,对不起......