boost::streams::output 过滤器的意外行为
Unexpected behavior with boost::streams::output filter
我正在尝试实现一个用于日志记录的输出过滤器,并修改了一些示例代码,结果出现了意外。密码是
#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$
好像表达式'if(pri<3)'在第一次调用结构体成员函数时被求值一次。我希望每次有内容流式传输到 'out.'
时都会对其进行评估
顺便说一句,我正在努力开发一些可以记录到控制台(或者可能是文件)并且能够基于位图进行过滤的东西。 IOW,将定义一个掩码并在其中设置位,以使特定的输出语句能够实际写入某些内容。代码可能看起来像(掩码与启用一起使用)
<sometype> mask(0x0101);
out << enable(0x0010) << "log message" << endl; // not output
out << enable(0x0100) << "another log message" << endl; // is output
这似乎是开发人员可能想要做的常见事情,但我找不到要复制的示例。我正在努力寻找解决方案并 运行 解决这个问题。
谢谢!
编辑:尝试根据 Nikita 的建议添加 setPri class 以用作带有参数的 iomanip。仍未按预期工作 所有输出都被缓存,直到程序退出,然后最后一次 setPri() 插入生效。这就是 Boost iostream 的工作方式吗?
#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
//
// 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
这里的问题是 toupper_output_filter
在 pri
变量更改为 2
后应用于输出序列。
语句out << "test-1" << endl;
不过滤序列,它将符号放入缓冲区以供进一步处理。之后 pri=2;
和更多符号进入 out << "test-2" << endl;
处的缓冲区。在离开范围之前 out
过滤它的缓冲区并输出最终的符号序列。此时 pri
为 2
并打印所有行。
要解决此问题,您可以删除全局状态:
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
class 的主要思想是去除静态并用 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
我正在尝试实现一个用于日志记录的输出过滤器,并修改了一些示例代码,结果出现了意外。密码是
#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$
好像表达式'if(pri<3)'在第一次调用结构体成员函数时被求值一次。我希望每次有内容流式传输到 'out.'
时都会对其进行评估顺便说一句,我正在努力开发一些可以记录到控制台(或者可能是文件)并且能够基于位图进行过滤的东西。 IOW,将定义一个掩码并在其中设置位,以使特定的输出语句能够实际写入某些内容。代码可能看起来像(掩码与启用一起使用)
<sometype> mask(0x0101);
out << enable(0x0010) << "log message" << endl; // not output
out << enable(0x0100) << "another log message" << endl; // is output
这似乎是开发人员可能想要做的常见事情,但我找不到要复制的示例。我正在努力寻找解决方案并 运行 解决这个问题。
谢谢!
编辑:尝试根据 Nikita 的建议添加 setPri class 以用作带有参数的 iomanip。仍未按预期工作 所有输出都被缓存,直到程序退出,然后最后一次 setPri() 插入生效。这就是 Boost iostream 的工作方式吗?
#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
//
// 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
这里的问题是 toupper_output_filter
在 pri
变量更改为 2
后应用于输出序列。
语句out << "test-1" << endl;
不过滤序列,它将符号放入缓冲区以供进一步处理。之后 pri=2;
和更多符号进入 out << "test-2" << endl;
处的缓冲区。在离开范围之前 out
过滤它的缓冲区并输出最终的符号序列。此时 pri
为 2
并打印所有行。
要解决此问题,您可以删除全局状态:
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
class 的主要思想是去除静态并用 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