屏蔽#include在namespace {}块中?

时间:2010-05-19 20:00:40

标签: c++ namespaces include

编辑:我知道方法1本质上是无效的,可能会使用方法2,但我正在寻找最好的黑客或更好的解决方案来缓解猖獗的,可变的命名空间扩散。

我在一个名称空间中有多个类或方法定义,它们具有不同的依赖关系,并且希望尽可能使用最少的名称空间块或显式scopings,但是将#include指令与尽可能最好地使用它们的定义分组。我从来没有看到任何迹象表明可以告诉任何预处理器从#include内容中排除命名空间{}作用域,但是我在这里询问是否有类似的东西是可能的:(见底部解释为什么我想要死的东西简单)

// NOTE: apple.h, etc., contents are *NOT* intended to be in namespace Foo!

// would prefer something most this:
#pragma magic_namespace_backout(1) // FIXME: use actually existing directive
namespace Foo {

#include "apple.h"
B *A::blah(B const *x) { /* ... */ }

#include "banana.h"
int B::whatever(C const &var) { /* ... */ }

#include "blueberry.h"
void B::something() { /* ... */ }

} // namespace Foo

...

// over this:
#include "apple.h"
#include "banana.h"
#include "blueberry.h"

namespace Foo {
B *A::blah(B const *x) { /* ... */ }
int B::whatever(C const &var) { /* ... */ }
void B::something() { /* ... */ }
} // namespace Foo

...

// or over this:
#include "apple.h"
namespace Foo {
B *A::blah(B const *x) { /* ... */ }
} // namespace Foo

#include "banana.h"
namespace Foo {
int B::whatever(C const &var) { /* ... */ }
} // namespace Foo

#include "blueberry.h"
namespace Foo {
void B::something() { /* ... */ }
} // namespace Foo

我真正的问题是我有一些项目,其中模块可能需要分支,但在同一程序中具有来自分支的共存组件。我有类似FooA等的类,我称之为Foo :: A,希望能够像Foo :: v1_2 :: A那样痛苦地分支,其中某些程序可能需要Foo :: A和Foo :: V1_2 ::一个。我希望“Foo”或“Foo :: v1_2”只显示每个文件一次,如果可能的话,作为单个命名空间块。此外,我倾向于在需要它们的文件中的第一个定义的正上方找到#include指令块。什么是我最好的选择,或者我应该做什么而不是劫持命名空间?

6 个答案:

答案 0 :(得分:37)

只需将#include视为将包含文件的内容复制并粘贴到#include指令的位置。

这意味着,是的,包含文件中的所有内容都将位于命名空间内。

答案 1 :(得分:14)

问:你能否:
答:是的,你可以。 include语句在编译器甚至看到它之前的预处理期间完成。

问:这是个好主意 答:可能不会。

如果#include Apple.g没有命名空间标记会发生什么 现在你在全局命名空间中声明了苹果以及foo命名空间。

您应该尝试避免代码用户需要了解应该如何使用它的情况。如果您的文档总是#include foo命名空间内的苹果头文件,那么用户将无法读取并导致数小时的混淆。

答案 2 :(得分:2)

你有编辑这个问题吗?

您的示例中的第一个块是不可能的。您不能在命名空间或其他任何内容中找到命名空间,也不能从该命名空间块中包含的文件中禁用命名空间。它根本不可能那样做。

我个人更喜欢你的第一个选择。

编辑,好的......这是你可以做的事情(可能需要清理,未经测试):


#define MY_NAMESPACE Foo
#define NAMESPACE_WRAP(X) namespace MY_NAMESPACE { X }

#include "apple.h"
NAMESPACE_WRAP((B * A::blah(B const * x) {...}))

非常肯定NAMESPACE_WRAP不适用于那种事情,但你可能需要将它放在不同的标题或“.ipp”或其他任何内容中并执行此操作:


#define NAMESPACE_WRAP(HEADER) \
namespace MY_NAMESPACE { \
#include HEADER \
}

即使这可能也行不通,你必须超越我的知识,看看增强预处理器元编程库如何做包含宏。实际上,您可能会发现该库最终会使您想要的更容易。

无论如何,它不会像你想要的那样漂亮,恕我直言,就像你提出的第一个选择一样可读和直接。

答案 3 :(得分:2)

学会喜欢第三个例子,将它分成三个单独的文件。这真的是最明确的方式。

如果您确实要在其他命名空间中包含文件,可以将}作为包含文件的第一个字符,并将namespace Whatever {放在最后。但这太糟糕了。

答案 4 :(得分:0)

可能每个模块都应该引用“Foo :: A”类,你可以将宏定义放在需要其他版本“A”的模块的开头。

#include "apple.h"
#include "apple1_2.h"

//this module uses Version 1.2 of "Apple" class
#define Apple v1_2::Apple
namespace Foo {
B *A::blah(B const *x) 
{
    Foo::Apple apple; //apple is of type Foo::v1_2::Apple
    /* ... */ 
} 
int B::whatever(C const &var) { /* ... */ }
void B::something() { /* ... */ }
} // namespace Foo
#undef Apple

但这会让代码更难理解。也许,如果您需要在对象的实现之间进行选择,您最好使用工厂函数。这将使你的意图在整个代码中明确。

AppleBaseClass* createApple(int version)
{
    if(version == 0)
        return new Foo::Apple;
    else if(version == 1)
        return new Foo::v1_2::Apple;
}
//usage
AppleBaseClass* apple = createApple(apple_version);

//compile-time equivalent
//metafunction CreateApple
template<int version> struct CreateApple {};
template<>
struct CreateApple<0> 
{
    typedef Foo::Apple ret;
};
template<>
struct CreateApple<1> 
{
    typedef Foo::v1_2::Apple ret;
};
//usage
CreateApple<apple_version>::ret apple;

答案 5 :(得分:0)

方法2一直 我总是使用这些简单的规则:

1。)源代码应清晰,易于理解和防伪。
- 一个好的产品不是由一个人建造的。简单,直观且易于理解的格式化将使每个人的生活更加快乐。

2。)如果最终产品没有性能差异,请遵守规则#1
- 对于那些不利于最终客户的事情而言,开发人员没有任何意义。

3。)优雅的设计总能正常运作,所以规则#2始终适用 - 同样的规则适用于上帝,带上镜子,看看自己:)