假设我有一个包含以下数据成员的员工对象:
class Employee {
private:
int _id;
std::string _name;
std::string _address;
std::string _city;
std::string _state;
std::string _country;
std::string _phone;
double _salary;
...
}
我想以两种不同的方式输出它:
XML
<Employee>
<id>12345</id>
<name>Jack Dough</name>
<address>24437 Princeton</address>
<city>Dearborn</city>
<state>Michigan</state>
<country>USA</country>
<phone>303-427-0153</phone>
<salary>140000</salary>
</Employee>
和JSON一样:
id: 12345
name: Jack Dough
address: 24437 Princeton
city: Dearborn
state: Michigan
country: USA
phone: 303-427-0153
salary: 140000
我如何使用流操纵器进行此操作? 例如:
Employee* employee = new Employee(12345, "Jack Dough", "24437 Princeton", "Dearborn", "Michigan", "USA", "303-427-0153", 140000.00);
cout << toXML << employee;
cout << toJSON << employee;
答案 0 :(得分:2)
首先,除非真的需要将其作为单独的操纵符实现,否则请考虑其他路径。两个显而易见的可能性是自定义区域设置,或者只是执行格式化并将结果作为字符串返回的函数。前者看起来像:
std::locale myLoc(std::locale(), XML_formatter);
cout.imbue(myLoc);
cout << employee;
这使得格式化样式通常对于流是持久的。如果你真的需要在同一个流中混合不同的样式,那么函数版本要简单得多:
std::string toXML(Employee const &e) {
std::stringstream ret;
ret << "Employee>\n<id>" << id << "</id>"
<< // ...
return ret.str();
}
// ...
cout << toXML(employees[i]);
如果你真的别无选择,只能将其作为一个单独的操纵器来实现,那么你需要存储一个标志来指示流中的当前格式。 Streams以xalloc
,iword
和pword
的形式提供内存管理界面。基本上,xalloc
为您分配一个单词。 iword
使您可以访问该单词作为对long的引用,pword
使您可以访问它作为指向void的指针。在您的情况下,您显然只需要一个或两个位,因此您可能希望使用iword
并定义几个位来指定类型的格式。您的toXML
和toJSON
操纵符会设置相应的位,operator<<
会读取它们以控制其行为。它很笨拙和丑陋,但如果你愿意付出一点努力,它确实有效。
答案 1 :(得分:1)
我如何使用流操纵器进行此操作?
我会告诉你如何,但请记住,这不是去这里的方式。专用(成员)功能或一些花哨的OOP模式是一种更好的方法。
那就是说你可以将任意数据附加到流对象上。为此,您首先需要该数据的“id”。你可以使用(update m k (fnil conj []) v)
:
std::ios_base::xalloc
使用返回的号码,您可以通过static int formatId = ios_base::xalloc();
返回的引用获得(写入)long
的访问权限。 (还有std::ios_base::iword
来获得std::ios_base::pword
。)
然后,流操纵器只是可以用流(引用)调用的东西,返回另一个流引用:
void *
(注意:邪恶的魔法数字,替换为更好的设计!)
这里我只是设置了一个“标志”,最后,在输出函数(运算符)中,我可以检查最后使用了哪个操纵器(如果有的话):
ostream & toFoo(ostream & stream) {
stream.iword(formatId) = 1;
return stream;
}
ostream & toBar(ostream & stream) {
stream.iword(formatId) = 2;
return stream;
}
嗯,就是这样。我测试了:
struct FooBar {};
ostream & operator<<(ostream & stream, FooBar const &) {
switch (stream.iword(formatId)) {
case 1: stream << "foo"; break;
case 2: stream << "bar"; break;
default: stream << "wild foobar";
}
return stream;
}