C++ std::facet对象上的可变标志
我正在尝试创建一些I/O操纵器,以允许用户修改自定义类型的输出格式 假设我有一个C++ std::facet对象上的可变标志,c++,C++,我正在尝试创建一些I/O操纵器,以允许用户修改自定义类型的输出格式 假设我有一个Foo对象:我可能想要以一种良好的、人类可读的格式(漂亮的打印)输出它,或者我可能想要以压缩的形式打印它以在序列化时节省空间 因此,最好有自定义I/O操纵器,如condensed和pretty,它们可以修改刻面的内部标志,因此我可以说: Foo f; ... std::cout << pretty << f; // output human-readable format std::cou
Foo
对象:我可能想要以一种良好的、人类可读的格式(漂亮的打印)输出它,或者我可能想要以压缩的形式打印它以在序列化时节省空间
因此,最好有自定义I/O操纵器,如condensed
和pretty
,它们可以修改刻面的内部标志,因此我可以说:
Foo f;
...
std::cout << pretty << f; // output human-readable format
std::cout << condensed << f; // output condensed format
然后我可以创建I/O操纵器,如:
template <class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& pretty(std::basic_ostream<CharT, Traits>& os)
{
my_facet<CharT>* facet = new my_facet();
facet->set_pretty(true);
facet->set_condensed(false);
std::locale loc = std::locale(os.getloc(), facet);
os.imbue(loc);
return os;
}
问题是每个I/O操纵器都必须重新创建刻面对象,因此以前设置的标志将丢失。原因是无法访问对现有方面的非常量引用
我想说:
template <class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& operator << (std::basic_ostream<CharT, Traits>& os,
const indent& ind)
{
const my_facet<CharT>& facet = std::use_facet<my_facet>(os.getloc());
facet.set_indentation(ind.value()); // Error: facet is const!
return os;
}
存储自定义格式状态的公认方法是使用
std::ios_base::xalloc
分配的内存。例如(节选,):
类MyFancyManipulator
{
静态int-myidx;
int st;
公众:
MyFancyManipulator(int-st):st(st){};
模板朋友
std::basic_ostream&operator将格式状态和标志存储在一个方面中,而不是存储在一个方面。@n.m.:是否将其扩展为一个答案?这是正确的解决方案。
std::cout << pretty << indent(4) << f;
template <class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& operator << (std::basic_ostream<CharT, Traits>& os,
const indent& ind)
{
const my_facet<CharT>& facet = std::use_facet<my_facet>(os.getloc());
facet.set_indentation(ind.value()); // Error: facet is const!
return os;
}
std::cout << pretty << indent(3) << etc ...
class MyFancyManipulator
{
static int myidx;
int st;
public:
MyFancyManipulator(int st) : st(st) {};
template <typename Ch, typename Tr> friend
std::basic_ostream<Ch, Tr>& operator<< (std::basic_ostream<Ch, Tr>& str,
const MyFancyManipulator& man) {
//
// Transfer state from the manipulator to the stream
//
str.iword(MyFancyManipulator::myidx) = man.st;
return str;
}
};
// Allocate index for the state variable
// This is thread safe per C++14 standard
int MyFancyManipulator::myidx = std::ios_base::xalloc();
// ... In some custom operator<<
int state = str.iword(MyFancyManipulator::myidx);