C++ std::facet对象上的可变标志

C++ std::facet对象上的可变标志,c++,C++,我正在尝试创建一些I/O操纵器,以允许用户修改自定义类型的输出格式 假设我有一个Foo对象:我可能想要以一种良好的、人类可读的格式(漂亮的打印)输出它,或者我可能想要以压缩的形式打印它以在序列化时节省空间 因此,最好有自定义I/O操纵器,如condensed和pretty,它们可以修改刻面的内部标志,因此我可以说: Foo f; ... std::cout << pretty << f; // output human-readable format std::cou

我正在尝试创建一些I/O操纵器,以允许用户修改自定义类型的输出格式

假设我有一个
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);