代码之家  ›  专栏  ›  技术社区  ›  Jeff

屏蔽#包含在命名空间{}块中?

  •  16
  • Jeff  · 技术社区  · 14 年前

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

    我在一个名称空间中有多个具有不同依赖关系的类或方法定义,并且希望使用尽可能少的名称空间块或显式作用域,但在分组时#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
    

    6 回复  |  直到 14 年前
        1
  •  49
  •   Timbo    14 年前

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

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

        2
  •  18
  •   Loki Astari    14 年前

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

    问:这是个好主意吗。

    如果在没有名称空间标记的情况下包含Apple.g会发生什么。

    您应该尽量避免出现这样的情况:您的代码的用户需要了解应该如何使用它。如果您的文档中说总是#将apple头文件包含在foo名称空间中,那么用户将无法读取该位,从而导致数小时的混乱。

        3
  •  2
  •   dash-tom-bang    14 年前

    学会爱上第三个例子,把它分成三个独立的文件。那真的是最清楚的方法了。

    如果您真的想在其他名称空间中包含文件,可以将 } 作为include文件的第一个字符 namespace Whatever { 最后。但这将是可怕的。

        4
  •  2
  •   Edward Strange    14 年前

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

    编辑,好的…你可以做一些事情(可能需要清理,未经测试):

    
    #define MY_NAMESPACE Foo
    #define NAMESPACE_WRAP(X) namespace MY_NAMESPACE { X }
    
    #include "apple.h"
    NAMESPACE_WRAP((B * A::blah(B const * x) {...}))
    

    很确定名称空间\u WRAP对这种类型的东西不起作用,所以您可能需要将它放在不同的头文件或“.ipp”或其他什么文件中,然后执行以下操作:

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

    即使这样也可能行不通,您必须超越我的知识范围,看看boost预处理器元编程库是如何包含宏的。你可能会发现,这个库最终会让你想要的东西变得更容易。

        5
  •  1
  •   Alsk    14 年前

    可能,每个模块都应该引用“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;
    
        6
  •  0
  •   YeenFei    14 年前

    方法2一路。
    我总是遵循这些简单的规则:

    1.)源代码应清晰、易于理解和防伪。
    -好的产品不是一个人造出来的。简单,直观和易于遵循的格式将使每个人的生活更幸福。

    2.)如果最终产品没有性能差异,请遵守规则1
    -对于开发人员来说,把脑细胞花在对最终客户没有好处的事情上是毫无意义的。

    3.)优雅的设计总是很好用的,所以规则2总是正确的。
    -同样的规则也适用于上帝,照镜子看看自己:)