gpt4 book ai didi

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

转载 作者:搜寻专家 更新时间:2023-10-31 02:24:14 25 4
gpt4 key购买 nike

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

假设我有一个 Foo 对象:我可能想以一种漂亮的、人类可读的格式输出它( pretty-print ),或者我可能想以一种压缩的形式打印它以保存序列化时的空间。

所以,如果有像 condensedpretty 这样的自定义 I/O 操纵器会很好,它们会修改 facet 的内部标志,所以我可以说类似的话:

Foo f;

...

std::cout << pretty << f; // output human-readable format
std::cout << condensed << f; // output condensed format

我经常遇到的问题是,一旦一个 facet 对象被创建,它只能在以后使用 std::use_facet 来检索,它返回一个 const 引用。这意味着我以后无法修改任何内部方面标志。

考虑一个简单的方面:

class my_facet : public std::locale::facet
{
public:

my_facet() : m_pretty(false), m_condensed(false)
{ }

void set_pretty(bool b) { m_pretty = b; }

void set_condensed(bool b) { m_condensed = b; }

static std::locale::id id;

private:

bool m_pretty;
bool m_condensed;
};

然后我可以创建 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;
}

效果很好......但是如果我想让用户指定额外的标志或格式选项,比如允许用户指定多个空格的 indentation 选项怎么办?缩进,像这样:

std::cout << pretty << indent(4) << f;

问题是每个 I/O 操纵器都必须重新创建 facet 对象,因此之前设置的标志会丢失。原因是无法访问对现有分面的非常量引用。

我想说:

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

...但是当然,这行不通,因为 facetconst。我能看到的解决这个问题的唯一方法是使所有内部标志 可变,这是荒谬的。

所以,我觉得我做错了。似乎没有任何方法可以获得对现有方面的非常量引用,所以我认为我正在以错误的方式处理这整件事。

那么,这种事情通常是如何实现的呢?我如何编写可以链接在一起以设置不同标志的 I/O 操纵器,例如:

std::cout << pretty << indent(3) << etc ...

最佳答案

存储自定义格式化状态的公认方法是使用 std::ios_base::xalloc 分配的内存。例如(删节,live demo with full code here):

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);

关于c++ - std::facet 对象上的可变标志,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28271898/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com