想到的最简单的方法是从创建标签类型及其单个实例开始:
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>";
}