如何创建一个操纵器来调用流中下一个对象中的特定函数?
How to create a manipulator that would call a specific function in the next object in the stream?
假设我有一个 class 如下:
class A
{
...private members
public:
void write_text(std::ostream& os); //writes members as text
void write_binary(std::ostream& os); //writes objects as binary
};
如何创建一个类似 text
和 binary
的操纵器,具体取决于我可以调用适当的函数 write_text()
或 write_binary()
来写入文件流,如下所示:
std::ofstream file1("textfile.txt");
std::ofstream file2("binfile.bin");
A obj; // assume obj has data members set
file1<<text<<obj; // here obj.write_text() should be invoked
file2<<binary<<obj; // here obj.write_binary() should be invoked
我是否需要像这样 example 那样在流中存储状态或变量之类的东西才能做到这一点,还是有更简单的方法?
标准用于操纵输入和输出操作的主要方式有两种。
1。在流状态中存储值
您可以使用 std::ios_base::xalloc()
.
在流中存储格式化状态
这为您提供了每个流中的 long
和 void*
值,您可以使用 iword()
/ pword()
访问这些值。
这与 std::hex
, std::boolalpha
等标准 io 操纵器使用的机制相同。
请注意,如果您更改流状态,它将保持该状态,直到您再次更改它,例如:
std::cout << std::hex << 16; // will be outputted in hexadecimal
std::cout << 12; // will still be outputted in hexadecimal
std::cout << std::dec << 16; // will be outputted in decimal
std::cout << 12; // still decimal
你可以,例如为您的 A
class:
实现它
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
};
// this gives us the unique index we need for pword() / iword()
inline int getAFormatIndex() {
static int idx = std::ios_base::xalloc();
return idx;
}
std::ostream& operator<<(std::ostream& os, A const& a) {
std::ostream::sentry s{os};
if(!s) return os;
if(os.iword(getAFormatIndex()) == 0)
a.write_text(os);
else
a.write_binary(os);
return os;
}
struct text_t {};
struct binary_t {};
inline constexpr text_t text;
inline constexpr binary_t binary;
// change to text mode
std::ostream& operator<<(std::ostream& os, text_t const&) {
os.iword(getAFormatIndex()) = 0;
return os;
}
// change to binary mode
std::ostream& operator<<(std::ostream& os, binary_t const&) {
os.iword(getAFormatIndex()) = 1;
return os;
}
operator<<
for A
检查当前存储在流中的格式类型(0为文本,1为二进制)并调用相应的方法
text
& binary
是 io 操纵器,当应用于流时会更改流状态。
用法示例:
A a;
std::cout << text << a;
std::cout << binary << a;
std::cout << a; // still in binary format
2。包装函数
您还会在标准库中遇到的另一种 io 操纵器是更改单个元素的输入/输出的包装器。
这方面的例子是 std::quoted
, std::get_money
, std::put_money
,等等...
这些函数只改变单个操作的格式,与上面的方法相反,改变所有后续输入/输出操作的格式。
示例:
std::cout << std::put_money(12.34); // will be formatted as monetary value
std::cout << 12.34; // normal double output
std::cout << std::quoted("foo"); // -> "foo"
std::cout << "foo"; // -> foo
你可以,例如为您的 A
class:
实现它
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
};
std::ostream& operator<<(std::ostream& os, A const& a) {
std::ostream::sentry s{os};
if(!s) return os;
a.write_text(os);
return os;
}
struct binary_impl { A const& a; };
std::ostream& operator<<(std::ostream& os, binary_impl const& b) {
std::ostream::sentry s{os};
if(!s) return os;
b.a.write_binary(os);
return os;
}
binary_impl binary(A const& a) {
return { a };
}
// text is the default, so we need no wrapper
A const& text(A const& a) {
return a;
}
- 我们基本上使用了一个包装器对象 (
binary_impl
),它为 A
个对象实现了不同的 operator<<
。
用法示例:
A a;
std::cout << text(a);
std::cout << binary(a);
std::cout << a; // default is text format
上面列出的方法只是标准库本身使用的方法(因此可能是最受认可的方法)。
你当然也可以为它创建你自己的自定义方法,例如通过使用 return 对象的成员方法,将以特定方式序列化对象:
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
struct as_text_t { A const& a; };
struct as_binary_t { A const& a; };
as_text_t as_text() const {
return { *this };
}
as_binary_t as_binary() const {
return { *this };
}
};
std::ostream& operator<<(std::ostream& os, A::as_text_t const& el) {
std::ostream::sentry s{os};
if(!s) return os;
el.a.write_text(os);
return os;
}
std::ostream& operator<<(std::ostream& os, A::as_binary_t const& el) {
std::ostream::sentry s{os};
if(!s) return os;
el.a.write_binary(os);
return os;
}
用法:
A a;
std::cout << a.as_text();
std::cout << a.as_binary();
假设我有一个 class 如下:
class A
{
...private members
public:
void write_text(std::ostream& os); //writes members as text
void write_binary(std::ostream& os); //writes objects as binary
};
如何创建一个类似 text
和 binary
的操纵器,具体取决于我可以调用适当的函数 write_text()
或 write_binary()
来写入文件流,如下所示:
std::ofstream file1("textfile.txt");
std::ofstream file2("binfile.bin");
A obj; // assume obj has data members set
file1<<text<<obj; // here obj.write_text() should be invoked
file2<<binary<<obj; // here obj.write_binary() should be invoked
我是否需要像这样 example 那样在流中存储状态或变量之类的东西才能做到这一点,还是有更简单的方法?
标准用于操纵输入和输出操作的主要方式有两种。
1。在流状态中存储值
您可以使用 std::ios_base::xalloc()
.
在流中存储格式化状态
这为您提供了每个流中的 long
和 void*
值,您可以使用 iword()
/ pword()
访问这些值。
这与 std::hex
, std::boolalpha
等标准 io 操纵器使用的机制相同。
请注意,如果您更改流状态,它将保持该状态,直到您再次更改它,例如:
std::cout << std::hex << 16; // will be outputted in hexadecimal
std::cout << 12; // will still be outputted in hexadecimal
std::cout << std::dec << 16; // will be outputted in decimal
std::cout << 12; // still decimal
你可以,例如为您的 A
class:
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
};
// this gives us the unique index we need for pword() / iword()
inline int getAFormatIndex() {
static int idx = std::ios_base::xalloc();
return idx;
}
std::ostream& operator<<(std::ostream& os, A const& a) {
std::ostream::sentry s{os};
if(!s) return os;
if(os.iword(getAFormatIndex()) == 0)
a.write_text(os);
else
a.write_binary(os);
return os;
}
struct text_t {};
struct binary_t {};
inline constexpr text_t text;
inline constexpr binary_t binary;
// change to text mode
std::ostream& operator<<(std::ostream& os, text_t const&) {
os.iword(getAFormatIndex()) = 0;
return os;
}
// change to binary mode
std::ostream& operator<<(std::ostream& os, binary_t const&) {
os.iword(getAFormatIndex()) = 1;
return os;
}
operator<<
forA
检查当前存储在流中的格式类型(0为文本,1为二进制)并调用相应的方法text
&binary
是 io 操纵器,当应用于流时会更改流状态。
用法示例:
A a;
std::cout << text << a;
std::cout << binary << a;
std::cout << a; // still in binary format
2。包装函数
您还会在标准库中遇到的另一种 io 操纵器是更改单个元素的输入/输出的包装器。
这方面的例子是 std::quoted
, std::get_money
, std::put_money
,等等...
这些函数只改变单个操作的格式,与上面的方法相反,改变所有后续输入/输出操作的格式。 示例:
std::cout << std::put_money(12.34); // will be formatted as monetary value
std::cout << 12.34; // normal double output
std::cout << std::quoted("foo"); // -> "foo"
std::cout << "foo"; // -> foo
你可以,例如为您的 A
class:
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
};
std::ostream& operator<<(std::ostream& os, A const& a) {
std::ostream::sentry s{os};
if(!s) return os;
a.write_text(os);
return os;
}
struct binary_impl { A const& a; };
std::ostream& operator<<(std::ostream& os, binary_impl const& b) {
std::ostream::sentry s{os};
if(!s) return os;
b.a.write_binary(os);
return os;
}
binary_impl binary(A const& a) {
return { a };
}
// text is the default, so we need no wrapper
A const& text(A const& a) {
return a;
}
- 我们基本上使用了一个包装器对象 (
binary_impl
),它为A
个对象实现了不同的operator<<
。
用法示例:
A a;
std::cout << text(a);
std::cout << binary(a);
std::cout << a; // default is text format
上面列出的方法只是标准库本身使用的方法(因此可能是最受认可的方法)。
你当然也可以为它创建你自己的自定义方法,例如通过使用 return 对象的成员方法,将以特定方式序列化对象:
class A {
public:
void write_text(std::ostream& os) const {
os << "TEXT";
}
void write_binary(std::ostream& os) const {
os << "BINARY";
}
struct as_text_t { A const& a; };
struct as_binary_t { A const& a; };
as_text_t as_text() const {
return { *this };
}
as_binary_t as_binary() const {
return { *this };
}
};
std::ostream& operator<<(std::ostream& os, A::as_text_t const& el) {
std::ostream::sentry s{os};
if(!s) return os;
el.a.write_text(os);
return os;
}
std::ostream& operator<<(std::ostream& os, A::as_binary_t const& el) {
std::ostream::sentry s{os};
if(!s) return os;
el.a.write_binary(os);
return os;
}
用法:
A a;
std::cout << a.as_text();
std::cout << a.as_binary();