编辑:我知道方法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指令块。什么是我最好的选择,或者我应该做什么而不是劫持命名空间?
答案 0 :(得分:37)
只需将#include视为将包含文件的内容复制并粘贴到#include指令的位置。
这意味着,是的,包含文件中的所有内容都将位于命名空间内。
答案 1 :(得分:14)
如果#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始终适用 - 同样的规则适用于上帝,带上镜子,看看自己:)