c++创建自己的格式化标志
c++ creating own formatting flags
我需要为输出文件的格式创建新的标志。我有
class foo{
bar* members;
ofstream& operator<<(ofstream&);
ifstream& operator>>(ifstream&);
};
我想像一样使用它
fstream os('filename.xml');
foo f;
os << xml << f;
os.close();
这将保存一个xml文件。
fstream os('filename.json');
foo f;
os << json << f;
os.close();
这是一个json文件。
我该怎么做?
您可以轻松创建自己的操纵器,或者劫持现有的标志或使用std::ios_base::xalloc
来获得新的流特定存储器,例如(在Foo
:的实现文件中
static int const manipFlagId = std::ios_base::xalloc();
enum
{
fmt_xml, // Becomes the default.
fmt_json
};
std::ostream&
xml( std::ostream& stream )
{
stream.iword( manipFlagId ) = fmt_xml;
return stream;
}
std::ostream&
json( std::ostream& stream )
{
stream.iword( manipFlagId ) = fmt_json;
return stream;
}
std::ostream&
operator<<( std::ostream& dest, Foo const& obj )
{
switch ( dest.iword( manipFlagId ) ) {
case fmt_xml:
// ...
break;
case fmt_json:
// ...
break;
default:
assert(0); // Or log error, or abort, or...
}
return dest;
}
在头中声明xml
和json
,工作就完成了。
(话虽如此,我认为这有点滥用操纵器。像xml这样的格式超越了简单的本地格式最好由一个单独的类处理,该类拥有ostream
,并且写入整个流,而不仅仅是单个对象。)
此问题是iostream库中最大的缺陷。
James Kanze的解决方案是一个局部的解决方案,它将在您自己的类中工作,但通常情况下,对象被赋予了一种独特的流式传输方式。
我通常的方法是创建我自己的包装器类,其中包含一个可以传递到流中的函数,并且xml将包含对xml_node()
或xml_attribute()
的重载,例如
os << xml_attribute( "Id", id );
将属性Id设置为xml格式的变量中的任何属性。
我还编写了节点作用域,因此它们将在构造时编写节点打开文本流,并在销毁时自动编写关闭逻辑。
与James Kanze的解决方案相比,我的方法的优势在于它是可扩展的。我认为詹姆斯·坎泽的结束语表明他不支持他的解决方案,可能会使用更像我的解决方案。
使用上述解决方案,为了添加更多格式,您必须编辑运算符<lt;函数,而json格式的代码将是一组完全不同的函数,如果您添加了另一种格式,则无需编辑任何现有代码即可为其添加代码。
顺便说一句,对于输入,对于XML,您将使用现有的DOM或SAX解析器,而不会以这种方式直接使用iostream。
想到的最简单的方法是从创建一个标记类型及其单个实例开始:
struct JsonStreamTag {} json;
然后让这样一个标签构造一个对象来包装流:
class JsonStream {
public:
// (1)
friend JsonStream operator<<(std::ostream& ostream, const JsonStreamTag&) {
return JsonStream(ostream);
}
// (2)
template<class T>
friend JsonStream& operator<<(JsonStream& json_stream, const T& value) {
write_json(json_stream.ostream, value); // (3)
return json_stream;
}
protected:
JsonStream(std::ostream& ostream) : ostream(ostream) {}
private:
std::ostream& ostream;
};
构造函数是protected
,以确保您只能使用some_ostream << json
(1)来构造JsonStream
。另一个插入运算符(2)执行实际格式化。然后为每个相关类型定义write_json()
(3)的过载:
void write_json(std::ostream& stream, int value) {
stream << value;
}
void write_json(std::ostream& stream, std::string value) {
stream << '"' << escape_json(value) << '"';
}
// Overloads for double, std::vector, std::map, &c.
或者,省略(2),改为添加operator<<(JsonStream&, T)
的过载。
然后按照相同的过程使用XmlStreamTag
和write_xml()
写入相应的XmlStream
。这假设您的输出可以完全由您正在编写的特定值构建;如果你需要在你要写的每个文件中都有相同的页眉或页脚,只需使用构造函数和析构函数:
XmlStream(std::ostream& ostream) : ostream(ostream) {
ostream << "<?xml version="1.0"?><my_document>"
}
~XmlStream() {
ostream << "</my_document>";
}
- C++格式化输出问题
- 格式化浮点值:返回默认值
- 即使使用调试编译标志,表达式也是"optimized out"
- 在 CMake 中为每个目标设置编译器/链接器标志
- 自动格式化程序> >更改为>>
- 如何从C++中的格式化字符串派生整数?
- 将从格式化文本文件读取的文本数据存储到链表
- 在不使用系统的情况下从C++应用程序格式化 Linux 中的 SD 卡
- 高精度双精度的 Sprintf 格式化问题
- File.cpp.o:OpenPose 标志 CMakeFiles/.. 的多重定义/main.cpp.o:首先在这里定
- 在轮班操作后使用携带标志
- 如何找出引入AVX标志的内容
- 如何在 c++ 中格式化和访问 2D 矢量数组中的数据
- 叮当格式化程序多行格式配置错误
- I2C 文件描述符上的 I2C 总线可写/可读标志
- C ++是否有C ++ 17 OSX 10.13.6的标志
- 如何格式化我的文本文件以使其不会一遍又一遍地重复同一行?
- 从函数(不抛出函数)返回异常以进行消息格式化?
- 哪些是互斥的:位字段还是格式化标志?在c++中
- c++创建自己的格式化标志