4

現在、char* および var 引数を受け取り、それらを使用して printf を実行するロギング システムがあります。これは C スタイルの文字列でうまく機能しますが、もう少しすっきりしたものにしたいと思います。現在、std::stringstream を使用する場合、ロギング システムの外部で文字列ストリームを作成し、文字列ストリームによって指定された文字列に char* を使用する必要があります。次のようになります。

std::stringstream strStream;
strStream << "The value of x is: " << x;
logging::print( strStream.str().c_str() );

私が望むのは、パラメータを文字列ストリームで直接使用しているかのように関数に渡すことです。ユーザーの観点からは、次のようになります。

logging::printStream("The value of x is: " << x);

またはおそらく次のように:

logging::printStream("The value of x is: ", x);

ロギング システムの関数の外で文字列ストリームを作成しなくても、stringstream を使用できるようにロギングを使用する方法はありますか?

シッピング ビルドで関数パラメーターのいずれかがコンパイルされないようにするマクロを作成するつもりなので、これは特に重要です。その外部で文字列ストリームを作成して渡す必要がある場合、マクロは役に立ちません。技術的には、この質問で話している文字列ストリームのことを行うマクロを作成できますが、常にそうなるとは限らないため、それはかなり面倒ですこのロギングで文字列ストリームを使用するため、標準ロギング用のマクロと、標準ロギング用のマクロを呼び出す文字列ストリームを使用するための別のマクロがあります。

4

5 に答える 5

1

以下は意図したとおりに機能します (テスト済み -- cerr への出力を logging::print に置き換えます):

#include<sstream>
#include<iostream>

class StringstreamLogger {
private:
    std::stringstream s;

public:
    StringstreamLogger () : s (std::ios_base::out) {
    }

    ~StringstreamLogger () {
    std::cerr << s.str () << std::endl; // logging::print (s.str ().c_str ());
    }

    std::stringstream& out () {
    return s;
    }
};

int main () {
    StringstreamLogger ().out () << "My log message";
    std::cerr << "Some later output to test for prompt logging (to ensure that logging is not delayed until the end of a block)" << std::endl;
}
于 2012-05-29T21:03:43.847 に答える
0

これを書くことができます:

print(static_cast<std::ostringstream&>(std::ostringstream() << "The value of x is: " << x).str().c_str());

多分それはあなたの好みに合っていますか?

于 2012-05-29T15:54:48.563 に答える
0

出力ストリーミング演算子をオーバーロードするカスタム型はどうですか?

struct logger
{
    std::stringstream ss_;

    template <typename T>
    friend logger& operator << (logger& l, T const& t) 
    {
    #ifdef DEBUG_MODE
        l.ss_ << t;
    #endif

        return l;
    }

    ~logger()
    {
    #ifdef DEBUG_MODE
        // output ss_.str().c_str() to your logger.
    #endif
    }
};

そして、出力をログに記録する必要があるときはいつでも

logger log;
log << "Log this stuff: " << x << '\n';
于 2012-05-30T02:59:14.707 に答える
0

出発点として、あなたは...

class Something {
public:
    std::ostream& error() const { ... code to return some std::ostream ... }
};

...

int main () {
    Something something;
    something.error() << "Frobnicate" << 4;
}

後で、オーバーロードされたストリーム演算子を使用して独自のプロキシ オブジェクトを追加できます (これは、 から派生した独自のストリームを作成するよりも簡単だと思いますstd::ostream)。

もちろん、すでにたくさんのロギング フレームワークがあります。まずはそれらを調べてください。

于 2012-05-29T16:11:38.247 に答える
0

私は 2 つの HACK ソリューションを思いつきましたが、うまくいくはずです。最初のものはスコープ解決演算子を使用しないため、より安全です。2 つ目は、noop int 変数を使用してスコープを偽装しています。

#define logging_printStream(token) { std::stringstream o; o << token; logging::print(o.str().c_str()); }

namespace logging { int noop; }
#define printStream(token) noop = 0; { std::stringstream o; o << token; logging::print(o.str().c_str()); }

int main(int argc, const char** argv)
{
    int i = 1;

    // MORE SAFE
    logging_printStream(i)
    logging_printStream("is this magic? " << (i ? "yes" : "no"))

    // LESS SAFE
    logging::printStream(i)
    logging::printStream("is this magic? " << (i ? "yes" : "no"))
}

17.6.4.3.2 のため、logging__printStream を logging_printStream に更新しました

17.6.4.3.2 グローバル名 [global.names]

名前と関数シグネチャの特定のセットは、常に実装用に予約されています。

  • 2 つのアンダースコア _ _ を含む名前、またはアンダースコアで始まり、その後に大文字が続く名前 (2.12) は、すべての使用のために実装に予約されています。
  • アンダースコアで始まる各名前は、グローバル名前空間で名前として使用するために実装に予約されています。

3.6.1 のため、main の宣言だけを残しました。

3.6.1 メイン関数 [basic.start.main]

プログラムには、プログラムの指定された開始である main と呼ばれるグローバル関数が含まれます。独立した環境のプログラムがメイン関数を定義する必要があるかどうかは、実装によって定義されます。実装は、メイン関数を事前定義してはなりません。この関数はオーバーロードされません。型 int の戻り値の型を持つ必要がありますが、それ以外の場合、その型は実装定義です。

于 2012-05-29T16:39:44.907 に答える