コンテキスト固有の情報をログメッセージに自動的に追加できるロギングフレームワークがあります。
これは、 /を使用してサブクラスの関数を呼び出してオブジェクトのコンテキストを取得するオフContext
クラス テンプレートを継承することによって実現されます。CRTP pattern
static polymorphism
Token()
ログを記録するときは、展開されるマクロを使用しGetLog()
ます。
- メンバー関数 内で
GetLog
、ロガーを取得して context を追加する基本クラスで見つかった場合Token
。 - フリー関数または非
Context
派生クラス内でGetLog
、グローバル名前空間で見つかった場合、ロガーを取得するだけです。
以下に完全に機能する例を示します。
問題
私の問題は、オフから派生したクラステンプレートがある場合ですContext
。たとえば、次のようになります。
template<typename T>
struct Foo : Context<Foo<T>>;
メンバー関数内にログインしようとすると、メソッドを従属名LOG
にするために接頭辞を付ける必要があります。this->
GetLog()
クラステンプレートメンバー関数を使用LOG
せずthis->
に解決する方法はありContext::GetLog()
ますか?
考え
Token
仮想関数を作成し、動的ポリモーフィズムを使用してコンテキストを取得します。欠点は、これによりすべてのロギング呼び出しに v-table ルックアップが追加されることです (多くのContext
派生オブジェクトを使用すると、コンパイラはインライン化できますか?) これをできるだけ無駄のないものにしたいと思います。- と を使用
std::enable_if
して、と派生オブジェクトstd::is_base_of
を区別します。私はこれを無料の機能で動作させることができるとは思いませんか?Context
non-Context
- その他の方法で?
これが実際の例です:
#include <iostream>
// stub logging object to make the example work - just logs to stdout
struct Log
{
template<typename T>
friend Log& operator<<(Log& l, T d)
{
std::cout << d;
return l;
}
friend Log& operator<<(Log& l, std::ostream& (*f)(std::ostream&))
{
std::cout << f;
return l;
}
};
Log gLog;
#define LOG GetLog()
// GetLog in the global namespace for non-Context derived classes, free functions etc
Log& GetLog()
{
return gLog;
}
// classes derive from this to add context specific information when logging
template<typename Self>
struct Context
{
// this GetLog adds prefix to Context derived classes
Log& GetLog()
{
static_cast<const Self*>(this)->Token(gLog); // add the Context's Token to the log
return gLog << ": ";
}
};
//-------------------------
template<typename T>
struct Foo : Context<Foo<T>>
{
void Func1()
{
LOG << __func__ << std::endl; // resolves to the global GetLog() free-function
}
void Func2()
{
this->LOG << __func__ << std::endl; // notice the 'this->' prefix to make GetLog() a dependent name
}
Log& Token(Log& l) const { return l << "Foo"; }
};
// logging inside a non-Context derived class
struct Bar
{
void Func()
{
LOG << __func__ << std::endl;
}
};
// logging inside a free function
void Baz()
{
LOG << __func__ << std::endl;
}
//-------------------------
int main()
{
Foo<int> f;
f.Func1();
f.Func2();
Bar b;
b.Func();
Baz();
exit(0);
}