boost :: streams :: output过滤器出现意外行为

时间:2016-09-26 20:50:43

标签: c++ boost-iostreams

我正在尝试为日志记录实现输出过滤器,并修改了一些带有意外结果的示例代码。代码是

#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;
}

定义TEST宏时遇到意外行为:

hbarta@itws007:~/Documents/C++/t-pri$ g++ -o t-pri t-pri.cpp
hbarta@itws007:~/Documents/C++/t-pri$ ./t-pri
pri: 4
hbarta@itws007:~/Documents/C++/t-pri$ g++ -DTEST -o t-pri t-pri.cpp
hbarta@itws007:~/Documents/C++/t-pri$ ./t-pri
pri: 4
test-1
test-2
hbarta@itws007:~/Documents/C++/t-pri$ 

似乎表达式&#39; if(pri&lt; 3)&#39;在首次调用结构成员函数时计算一次。我希望每次将某些内容流式传输到&#39; out时都会对其进行评估。&#39;

顺便说一下,我正在努力寻找记录到控制台(或者可能是文件)的东西,并且能够根据位图进行过滤。 IOW,将定义一个掩码并在其中设置位以使特定的输出语句能够实际写入某些内容。代码看起来像(掩码与启用相关)

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

这似乎是开发人员可能想做的常见事情,但我无法找到要复制的示例。我正努力寻求解决方案并遇到了这个问题。

谢谢!

编辑:尝试通过添加setPri类作为带有参数的iomanip,根据Nikita的建议添加到解决方案中。仍未按预期工作所有输出都将缓存,直到程序退出,然后最后一次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

1 个答案:

答案 0 :(得分:2)

此处的问题是toupper_output_filter变量更改为pri2应用于输出序列。

语句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