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 に答える