4

ライブ ロギング フレームワーク (Apache) によってコードが緊密に結合され、単体テストの記述が非常に難しくなるため、大規模なコードベースからロギング コードをモジュール化しようとしています。仮想テンプレート関数を使用できないという事実に固執しています。私の現在のアプローチは、次のように要約できます。

// Context.h
struct Logger
{
    template <typename... Args>
    void operator()(const char* aFormat, Args&&... aArgs)
    {
         // This function would ideally be virtual.
         // Is there a funky way to get this function to call
         // a derived class' implementation instead.
         std::cerr << "I don't want to see this printed" << std::endl;
    }
};

class Context
{
public:
    Context(const Logger& aLogger)
    :   iLogger(aLogger)
    {
    }

    template <typename... Args>
    void DEBUG(const char* aFormat, Args&&... aArgs)
    {
        iLogger(aFormat, aArgs...);
    }

private:
    const Logger& iLogger;
};


// MyType.h
#include "Context.h"

class MyType
{
public:
    MyType(Context& aCtx)
    :   iCtx(aCtx)
    {
        DEBUG("> ctor");
        DEBUG("< ctor. this=%p", this);
    }

private:
    template <typename... Args>
    void DEBUG(const char* aFormat, Args&&... aArgs)
    {
        iCtx.DEBUG(aFormat, aArgs...);
    }

    Context& iCtx;
};


// main.cpp
#include "MyType.h"

template <typename... Args>
static void StdErrLog(const char* aFormat, Args&&... aArgs)
{
    fprintf(stderr, aFormat, aArgs...);
}

struct StdErrLogger : public Logger
{

    // This function never gets called because it's not virtual.
    template <typename... Args>
    void operator(const char* aFormat, Args&&... aArgs)
    {
        StdErrLog(aFormat, aArgs...);
    }
}

int main(...)
{
    StdErrLogger logger; // For unit tests this could be 'EmptyLogger' for example.
    Context ctx(logger);

    MyType t(ctx);
}

これまでのところ、とても近いです。クラスをテンプレート化せずにこれを機能させるためにできることはありContextますか? コード ベースはまったくテンプレート化されておらず、面倒な作業が多いため、このルートをたどるのは非常に気が進まない.

テンプレートを関数レベルの範囲に抑えることでそれが可能であれば、解決策を見てとてもうれしく思います. 関数ポインターも受け入れられますが、可変個引数テンプレート関数のアドレスを取得できるかどうかはわかりません。

ありがとう

4

2 に答える 2

0

私は一歩下がって、数層のテンプレートをはがしました。生の関数ポインターは、私が必要としていたものを与えてくれました。また、関数として渡す場合、コンパイラがコードを生成しないほど賢くなることを願っていnullptrます。欠点は、各 LogFunction が faff を実行する必要があることva_list/start/endです。

// Context.h
typedef void (*LogFunction)(const char*, ...);

class Context
{
public:
    Context(LogFunction aDebugFunc)
    :   iDebugFunc(aDebugFunc)
    {
    }

    template <typename... Args>
    void DEBUG(const char* aFormat, Args&&... aArgs)
    {
        if (iDebugFunc)
        {
            iDebugFunc(aFormat, aArgs...);
        }
    }

private:
    LogFunction iDebugFunc;
};


// main.cpp
#include <cstdarg>

void StdErrLogger(const char* aFormat, ...)
{
    va_list args;
    va_start(args, aFormat);

    fprintf(stderr, aFormat, args);

    va_end(args);
}

int main(...)
{
    Context ctx(StdErrLogger);
    MyType t(ctx);
}
于 2013-09-07T22:00:36.017 に答える