如何递归访问父作用域?

时间:2013-02-21 16:30:56

标签: c++ scope

我尝试做一个花哨的宏来获得一些调试信息:你目前的范围名称!这可以通过例如一个断言。我试图让它递归:

// Global namespace
struct ScopeDef{ static const char* GetName() {return "";} };
typedef ScopeDef ScopeDefParent;

// Macro to place into your namespace/scope
#define NG_SCOPEDEF(scopename) \
    struct ScopeDef { \
        static const char* GetName() {return scopename;} \
        typedef ScopeDefParent Parent; \
    }; \
    typedef ScopeDef ScopeDefParent;

使用它像:

// Recursive template for testing
template< class T > void PrintImpl() {
    PrintImpl< T::Parent >();
    printf("::%s", T::GetName() );
}
template<> void PrintImpl< ::ScopeDef >() {}
template< class T > void PrintS() { PrintImpl<T>(); printf("\n");}

// Lets try it:
namespace First {
    NG_SCOPEDEF( "First" );
    namespace Second {
        NG_SCOPEDEF( "Second" );
        static void AFun() {
            // This prints "::First::Second"
            PrintS<ScopeDef>();
        }
    }
    struct Third {
        NG_SCOPEDEF( "Third" );
        static void BFun() {
            // This is endless recursion
            PrintS<ScopeDef>();
        }
    };
}

它在类范围内不起作用,因为定义的顺序无关紧要。

这不是一个好的解决方案。那么有没有办法以某种方式访问​​父作用域?在常规代码中,我只会限定(“:: First :: ScopeDef”),但这对宏来说没什么。

2 个答案:

答案 0 :(得分:1)

你可以在C ++中做这样的事情,你可以在每次打开一个范围时放入宏,让析构函数在范围退出时进行清理。此示例将打印出整个范围到stderr,此代码的输出如下。

main
main::First
main::First::Second
main::First::Second::DummyClass::DummyFunction
main::First
main

以下是代码:

#include <stdio.h>

class NG_SCOPE_CLASS;

NG_SCOPE_CLASS* NG_SCOPE_END = 0;

class NG_SCOPE_CLASS
{
public: 
    NG_SCOPE_CLASS(const char* scope)
    {
        _scope = scope;
        _prev = NG_SCOPE_END;
        NG_SCOPE_END = this;
    }
    ~ NG_SCOPE_CLASS()
    {
        NG_SCOPE_END = _prev;
    }
    void PrintScope()
    {
        if(_prev)
        {
            _prev->PrintScope();
            fprintf(stderr, "::");
        }
        fprintf(stderr, "%s", _scope);
    }
private:
    NG_SCOPE_CLASS* _prev;
    const char* _scope;
};

#define NG_SCOPE_PRINT { if(NG_SCOPE_END) { NG_SCOPE_END->PrintScope(); fprintf(stderr, "\n"); } }
#define NG_SCOPE(X) NG_SCOPE_CLASS _NG_SCOPE_CLASS(X)

// THAT'S IT FOR THE DEFINITIONS ABOVE, BELOW IS JUST SOME SAMPLE CODE.

class DummyClass
{
public:
    void DummyFunction()
    {
        NG_SCOPE("DummyClass::DummyFunction");
        NG_SCOPE_PRINT;
    }
};

int main(int argc, const char* argv[])
{
    NG_SCOPE("main");
    NG_SCOPE_PRINT;
    {
        NG_SCOPE("First");
        NG_SCOPE_PRINT;
        {
            NG_SCOPE("Second");
            NG_SCOPE_PRINT;
            DummyClass theDummyInstance;
            theDummyInstance.DummyFunction();
        }
        NG_SCOPE_PRINT;
    }
    NG_SCOPE_PRINT;
}

答案 1 :(得分:0)

为了完整性,我们的工作解决方案:

#if defined(_MSC_VER)
    // GCC solution below. Note MSVC gives warning about unused typedefs but can be suppressed.
    #define NG_SCOPEDEF(scopename) \
        struct ScopeDefTag { static const char* Name(){return (scopename);}; }; \
        typedef ::Scopes::Impl< ScopeDefTag, ScopeDef > ScopeDefHelper; \
        struct ScopeDef : ScopeDefHelper {}
#else
    // GCC seems to not look ahead.
    #define NG_SCOPEDEF(scopename) \
        struct ScopeDefTag { static const char* Name(){return (scopename);}; struct SDH : ::Scopes::Impl< ScopeDefTag, ScopeDef >{}; }; \
        struct ScopeDef : ScopeDefTag::SDH {}
#endif

namespace Scopes {
struct Chain {
    const char* const   m_Lit;
    const Chain* const  m_Prev;
    Chain(const char* lit, const Chain* prev) :m_Lit(lit), m_Prev(prev) {}
};

template< bool DMY = true >
struct RootScopeDef
{
    static const Chain chain;
    static const Chain* Get() { return &chain; }
};
// Being template just to have this in header:
template< bool DMY > const Chain RootScopeDef<DMY>::chain = Chain( "", 0 );


template< class TAG, class PARENT >
struct Impl {
    static const Chain chain;
    static const Chain* Get() { return &chain; }
    typedef PARENT Parent;
};

template< class TAG, class PARENT >
const Chain Impl<TAG, PARENT>::chain = Chain( TAG::Name(), &PARENT::chain );

} // namespace

// Global namespace
typedef Scopes::RootScopeDef<> ScopeDef;

它基于编译器的漏洞而且不符合标准! MSVS认为用作模板参数的ScopeDef不是下一个,因为它取决于那个非常类型的参数,所以它解析为父类,后面将被遮蔽。当宏放在模板中时,这也有效,因为MSVS懒惰地实例化它们。相反,海湾合作委员会似乎没有向前看并将SDH的基础解析为正确的基础。 MSVS会在这里产生一个无限循环的m_Prev引用。

底线:这为您打印出用于调试目的的命名空间和类提供了一种很好的方法,但也可用作例如类型的类型。模板的专业化!