私は自分のプロジェクト用の単純なロガーラッパーに取り組んでいます。これにより、バックエンドを簡単に交換できます。
これが私の理想的なインターフェースです。
log::error << "some" << " log " << "message";
私がそれを実装した方法は次のとおりです。
log::error#operator<<
Sink
一時オブジェクトを返します。Sink#operator<<
移動コンストラクターを返し*this
、定義します。Sink
完全なメッセージは、呼び出しチェーンの最後に呼び出されるのデストラクタで 利用できます。
考案された実装:
#include <iostream>
#include <string>
struct Sink {
Sink (std::string const& msg) : m_message(msg) {}
// no copying
Sink (Sink const& orig) = delete;
// move constructor
Sink (Sink && orig) : m_message(std::move(orig.m_message)) {};
// use the complete string in the destructor
~Sink() { std::cerr << m_message << std::endl;}
Sink operator<< (std::string const& msg) {
m_message.append(msg);
return std::move(*this);
}
std::string m_message;
};
struct Level {
Sink operator<< (std::string const& msg) { return Sink(msg); }
};
int main() {
Level log;
log << "this" << " is " << "a " << "test";
}
これは、ロギングを無効にするクリーンな方法が必要な場合を除いて、正常に機能します。チェーンを使用していなかった場合、ログ関数はプリプロセッサディレクティブを使用して関数のコンテンツを削除できます
void log (std::string) {
#ifdef LOGGING_ENABLED
// log message
#endif
}
次に、コンパイラーは空の関数呼び出しを最適化して削除します。しかし、私が達成しようとしているAPIでそれをどのように行うかはわかりません。glogがどういうわけかそれをするので、私はそれが可能であることを知っています。
このようなディレクティブを使用すると、優れたAPIを使用するという目的が無効になります。
#ifdef LOGGING_ENABLED
log << "this" << " is " << "a " << "test";
#endif
これらのタイプの連鎖呼び出しを無効にするクリーンな方法は何ですか?どんな助けでも大歓迎です。