2016-09-26 9 views
2

ログ出力用のフィルタを実装しようとしていて、予期しない結果が発生したサンプルコードが変更されました。コードはTESTマクロが定義されている場合、予期しない動作が発生したboost :: streams ::出力フィルタで予期しない動作が発生しました

#include <ctype.h>      // toupper 
#include <boost/iostreams/categories.hpp> // output_filter_tag 
#include <boost/iostreams/operations.hpp> // put 
#include <boost/iostreams/filtering_stream.hpp> 

// cobbled from http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/concepts/output_filter.html#examples 
// 
// g++ [-DTEST] -o t-pri t-pri.cpp 

using namespace std; 
namespace io = boost::iostreams; 

int pri=4; 

struct toupper_output_filter { 
    typedef char     char_type; 
    typedef io::output_filter_tag category; 

    template<typename Sink> 
    bool put(Sink& snk, char c) 
    { 
     if(pri<3) 
      return io::put(snk, /* toupper((unsigned char) c)*/ c); 
     else 
      return 0; 
    } 
}; 

int main(int argc, char**argv) 
{ 
    boost::iostreams::filtering_ostream out; 

    out.push(toupper_output_filter()); 
    cout << "pri: " << pri << endl; 
    out.push(cout); 

    out << "test-1" << endl; 
#ifdef TEST 
    pri=2; 
    out << "test-2" << endl; 
#endif 
    return 0; 
} 

です:

[email protected]:~/Documents/C++/t-pri$ g++ -o t-pri t-pri.cpp 
[email protected]:~/Documents/C++/t-pri$ ./t-pri 
pri: 4 
[email protected]:~/Documents/C++/t-pri$ g++ -DTEST -o t-pri t-pri.cpp 
[email protected]:~/Documents/C++/t-pri$ ./t-pri 
pri: 4 
test-1 
test-2 
[email protected]:~/Documents/C++/t-pri$ 

「(PRI < 3)もし」式の時に構造体メンバ一度だけ評価されるかのように思え関数が最初に呼び出されています。私は、何かが流出して「外出」するたびに評価されることを期待しています。

私は、コンソール(またはファイル)にログを記録し、ビットマップに基づいてフィルタリングする機能を備えています。 IOWでは、特定の出力ステートメントが実際に何かを書くことができるように、マスクが定義され、ビットがセットされます。 (マスクは有効でANDされている)のコードでは、これは開発者が行いたい場合があります事を、共通の一種のように思えるが、私はコピーする例を見つけることができません

<sometype> mask(0x0101); 
out << enable(0x0010) << "log message" << endl; // not output 
out << enable(0x0100) << "another log message" << endl; // is output 

ようになります。私は解決策に向かって作業しており、これに遭遇しました。

ありがとうございます!

編集:Nikitaの提案に従ってソリューションに追加しようとすると、setPriクラスを追加して、引数付きのiomanipとして使用します。まだ正常に動作していないプログラムが終了し最後にsetPri()が挿入されるまで、すべての出力がキャッシュされます。 Boost iostreamsはどのように動作するのでしょうか?

#include <boost/iostreams/categories.hpp> // output_filter_tag 
#include <boost/iostreams/operations.hpp> // put 
#include <boost/iostreams/filtering_stream.hpp> 

using namespace std; 
namespace io = boost::iostreams; 

// cobbled from http://www.boost.org/doc/libs/1_48_0/libs/iostreams/doc/concepts/output_filter.html#examples 
// 
// g++ -o to_upper to_upper.cpp 
// 
// Adding an iomanip with argument as in 
// http://stackoverflow.com/questions/20792101/how-to-store-formatting-settings-with-an-iostream 


// don't really want file scope variables... 
static int pri=0;  // value for a message 
static int mask=1;  // mask for enabled output (if pri&mask => output) 

static int priIDX() { // find index for storing priority choice 
    static int rc = ios_base::xalloc(); 
    return rc; 
} 

class setPri // Store priority in stream (but how to retrieve when needed?) 
{ 
    size_t _n; 
public: 
    explicit setPri(size_t n): _n(n) {} 
    size_t getn() const {return _n;} 
    friend ostream& operator<<(ostream& os, const setPri& obj) 
    { 
     size_t n = obj.getn(); 
     pri = n; 
     os << "setPri(" << n << ")";  // indicate update 
     return os; 
    } 
}; 

struct toupper_output_filter { 
    typedef char     char_type; 
    typedef io::output_filter_tag category; 

    template<typename Sink> 
    bool put(Sink& snk, char c) 
    { 
     if(pri & mask) // Should this char be sent to output? 
      return io::put(snk, c); 
     else 
      return 0; 
    } 
}; 

int main(int argc, char**argv) 
{ 
    boost::iostreams::filtering_ostream out; 

    out.push(toupper_output_filter()); 
    out.push(cout); 

    out << setPri(1) << " test-1" << endl; 
    out << setPri(2) << " test-2" << endl; 
    out << setPri(3) << " test-3" << endl; 
    return 0; 
} 

結果は

setPri(1) test-1 
setPri(2) test-2 
setPri(3) test-3 

答えて

2

ここでの問題は、pri変数は2に変更した後、toupper_output_filterが出力シーケンスに適用されるということです。

ステートメントout << "test-1" << endl;はシーケンスをフィルタリングしません。後続の処理のためにシンボルをバッファに入れます。その後、pri=2;以上のシンボルは、バッファーout << "test-2" << endl;に行きます。スコープを終了する前に、outはバッファであり、最終的なシンボルシーケンスを出力します。この時点でpri2であり、すべての行が印刷されています。

struct toupper_output_filter { 
    typedef char     char_type; 
    typedef io::output_filter_tag category; 

    int pri; 
    toupper_output_filter (int logLevel) 
    { 
     pri = logLevel; 
    } 

    template<typename Sink> 
    bool put(Sink& snk, char c) 
    { 
     if(pri<3) 
      return io::put(snk, /* toupper((unsigned char) c)*/ c); 
     else 
      return 0; 
    } 
}; 

そして、それを使用します:

あなたがグローバルな状態を削除することがある問題を修正するには

int main(int argc, char**argv) 
{ 
    boost::iostreams::filtering_ostream out; 

    int pri = 4; 
    out.push(toupper_output_filter(pri)); 
    cout << "pri: " << pri << endl; 
    out.push(cout); 

    out << "test-1" << endl; 
    out.pop(); 
    out.pop(); 

#ifdef TEST 
    pri=2; 

    out.push(toupper_output_filter(pri)); 
    out.push(cout); 
    out << "test-2" << endl; 
#endif 
    return 0; 
} 

アップデート: setPriクラスの主なアイデアは、静的な状態を削除することであり、 operator<<で優先度を操作します。解決のための ドラフト:

static int mask=1;  // mask for enabled output (if pri&mask => output) 

struct toupper_output_filter { 
    typedef char     char_type; 
    struct category : boost::iostreams::output_filter_tag {}; 

    int pri; 
    toupper_output_filter(int n) 
    { 
     pri = n; 
    } 

    template<typename Sink> 
    bool put(Sink& snk, char c) 
    { 
     if(pri & mask) // Should this char be sent to output? 
      return io::put(snk, c); 
     else 
      return 0; 
    } 
}; 

class setPri // Store priority in stream (but how to retrieve when needed?) 
{ 
    size_t _n; 
public: 
    explicit setPri(size_t n): _n(n) {} 
    size_t getn() const {return _n;} 
    friend boost::iostreams::filtering_ostream& operator<<(boost::iostreams::filtering_ostream& out, const setPri& obj) 
    { 
     if (!out.empty()) 
     { 
     out.pop(); 
     out.pop(); 
     } 
     out.push(toupper_output_filter(obj.getn())); 
     out.push(cout); 
     return out; 
    } 
}; 

int main(int argc, char**argv) 
{ 
    boost::iostreams::filtering_ostream out; 

    out << setPri(1) << " test-1" << endl; 
    out << setPri(2) << " test-2" << endl; 
    out << setPri(3) << " test-3" << endl; 
    return 0; 
} 

出力は次のとおりです。動作を説明するが、私はそれが私には理にかなっているかわからない

test-1 
test-3 
+0

。私が見つけた資料によると、 "その動作は、char以外の文字型のos.put( '\ n')(またはos.put(os.widen( '\ n'))の呼び出しと同じです。次にos.flush()を呼び出します。 私はendlが出力をフラッシュし、それが明らかに出力されないことを期待します。 ありがとう! – HankB

+0

あなたの 'enable(0x0010)'目標を達成するには、 'enable'とoverload [' operator << ']のユーザ定義型の作成を試みることができます(http://en.cppreference.com/w/cpp/language /演算子)を指定します。このオーバーロードは、適切な 'toupper_output_filter'インスタンスで' pop() '/' push() 'を行います。 – Nikita

+0

ありがとう、私はそれに行きましたが、まだ結果が期待されていません。私のOPへの私の追加を見てください。 – HankB

関連する問題