std::facet 对象上的可变标志
Mutable flags on a std::facet object
我正在尝试创建一些I/O操纵器以允许用户修改自定义类型的输出格式。
假设我有一个Foo
对象:我可能希望以漂亮的、人类可读的格式(漂亮的打印)输出它,或者我可能希望以精简形式打印它以节省序列化时的空间。
因此,最好有自定义的 I/O 操纵器(如 condensed
和 pretty
)来修改分面的内部标志,所以我可以这样说:
Foo f;
...
std::cout << pretty << f; // output human-readable format
std::cout << condensed << f; // output condensed format
我经常遇到的问题是,一旦创建了一个分面对象,以后只能通过使用返回常量引用的 std::use_facet
来检索它。 这意味着我以后无法修改任何内部分面标志。
考虑一个简单的方面:
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 操纵器都必须重新创建分面对象,因此先前设置的标志将丢失。 原因是无法访问对现有方面的非常量引用。
我想说:
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;
}
。但是,当然,这是行不通的,因为facet
const
. 我能看到的唯一方法是使所有内部标志mutable
,这是荒谬的。
所以,我感觉到我只是做错了。 似乎没有任何方法可以获取对现有方面的非常量引用,所以我认为我以错误的方式处理整个事情。
那么,这种事情通常是如何实现的呢? 如何编写可以链接在一起以设置不同标志的 I/O 操纵器,例如:
std::cout << pretty << indent(3) << etc ...
存储自定义格式状态的公认方法是使用由 std::ios_base::xalloc
分配的内存。例如(此处包含完整代码的删节版现场演示):
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);
相关文章:
- 即使使用调试编译标志,表达式也是"optimized out"
- 在 CMake 中为每个目标设置编译器/链接器标志
- File.cpp.o:OpenPose 标志 CMakeFiles/.. 的多重定义/main.cpp.o:首先在这里定
- 在轮班操作后使用携带标志
- 如何找出引入AVX标志的内容
- I2C 文件描述符上的 I2C 总线可写/可读标志
- C ++是否有C ++ 17 OSX 10.13.6的标志
- 每次使用带有LOCK_EX标志的LOCK_NB时,相同的程序/进程都会获取锁
- CMake 3.5 中的链接器标志位置
- 如何使用 gnu gcc 标志 -mpc32、-mpc64 和 -mpc80?
- 在 CMake 中添加全局编译标志
- -Wlifetime 标志的目的是什么?
- Visual Studio 19-17 库兼容性根据 GL 标志
- 标志 |= f == s[i],这个语句会做什么?
- Visual Studio 中是否有来自代码块的编译器标志的类似物?
- 如何在 clang 的自动会议中检查支持编译标志
- 使用 boost::p rogram_options 指定多个标志
- 如何告诉 gcc 显示您使用的优化标志列表
- 生成文件中隐式规则中的 -c 标志出错
- std::facet 对象上的可变标志