0

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

// 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"),但这对于宏来说不算什么。

4

2 回答 2

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;
}
于 2013-02-21T16:58:04.360 回答
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 不是下一个,因为它依赖于那个 typedef,所以它解析为父级,后面会被遮蔽。这也适用于将宏放置在模板中的情况,因为 MSVS 会延迟实例化它们。相反,GCC 似乎只是不向前看,而是将 SDH 的基础解析为正确的基础。MSVS 将在此处生成 m_Prev 引用的无限循环。

底线:这为您提供了一种打印命名空间和类以进行调试的好方法,但也可以用作模板专业化的类型!

于 2016-08-04T11:48:26.453 回答