【发布时间】:2009-10-05 06:40:58
【问题描述】:
是否可以为一个枚举定义多个输出运算符?我想用这个
std::ostream& operator<< (std::ostream& os, my_enum e);
操作员 (1) 打印人类可读的文本并 (2) 将其转换为一些代码以存储在数据库中。
谢谢
【问题讨论】:
标签: c++ operators operator-overloading enums
是否可以为一个枚举定义多个输出运算符?我想用这个
std::ostream& operator<< (std::ostream& os, my_enum e);
操作员 (1) 打印人类可读的文本并 (2) 将其转换为一些代码以存储在数据库中。
谢谢
【问题讨论】:
标签: c++ operators operator-overloading enums
创建将返回一些对象而不是处理打印的 ostream& 的包装器。在您的情况下,它将反对打印人类可读的值和打印数据库代码的对象。这是打印人类可读形式和整数形式的粗略示例。 ostream_enum_wrapper_human 类及其运算符 ostream_enum_wrapper_int 及其
#include <iostream>
using namespace std;
class ostream_enum_wrapper_human
{
public:
ostream& out;
ostream_enum_wrapper_human(std::ostream& _out) : out(_out){}
};
class ostream_enum_wrapper_int
{
public:
std::ostream& out;
ostream_enum_wrapper_int(std::ostream& _out) : out(_out){}
};
enum T{zero,one,two};
struct human_readable{} HumanReadable;
ostream_enum_wrapper_human operator << (ostream& out, human_readable){
return ostream_enum_wrapper_human(out);
}
struct print_int{} PrintInt;
ostream_enum_wrapper_int operator << (ostream& out, print_int){
return ostream_enum_wrapper_int(out);
}
ostream& operator << (ostream_enum_wrapper_human out, T t)
{
switch(t) {
case zero: out.out << "zero"; break;
case one: out.out << "one"; break;
case two: out.out << "two"; break;
}
return out.out;
}
ostream& operator << (ostream_enum_wrapper_int out, T t)
{
return out.out << static_cast<int>(t);
}
int main()
{
cout << HumanReadable << zero << PrintInt << zero << HumanReadable << two;
}
【讨论】:
您可以利用第一个参数的重载。
//For human-readable output
std::ostream& operator<< (std::ostream& os, my_enum e);
//For database; note the absence VVV of & sign here
std::ostream& operator<< (databasefmt fmt, my_enum e)
{
std::ostream& os = fmt.stream;
// Write data to os
// ...
return os;
}
struct databasefmt{
std::ostream& stream;
databasefmt(std::ostream & s) : stream(s) {};
};
然后编写将流转换为包装 databasefmt 类的流修饰符,以便该修改后的流的下一个输出将是您枚举的数据库输出。打印代码如下所示:
output_stream << "DATA: "<< database_format << my_enum::Value << "END OF DATA" ;
// Type: std::ostream | databasefmt | std::ostream |
和这样的包装器:
//Variable is needed to avoid confusing parentheses in output operators
struct databasefmt_converter_t {} database_format;
// we can't return reference, so we just return fairly small instance of wrapper
databasefmt operator<< (std::ostream& os, databasefmt_converter_t const&)
{ return databasefmt(os); }
【讨论】:
当然,为什么不呢?您必须创建一个实现写入数据库的ostream 派生类,这与ofstream 写入文件非常相似。魔鬼在细节中。
【讨论】:
首选的方法是使用 std::ios_base::xalloc 然后使用 std::ios_base::iword:
int getxalloc()
{
static const int ix = std::ios_base::xalloc();
return ix;
}
enum my_enum
{
zero,
one,
two,
};
std::ostream& operator<<(std::ostream& os, my_enum e)
{
switch (os.iword(getxalloc())
{
default:
case 0:
os << (int)e;
break;
case 1:
switch (e)
{
case zero:
os << "zero";
break;
case one:
os << "one";
break;
case two:
os << "two";
break;
default:
os << "unknown";
break;
}
break;
}
return os;
}
int main()
{
my_enum e = one;
std::cout.iword(getxalloc()) = 0;
std::cout << e << "\n"; // will output "1"
std::cout.iword(getxalloc()) = 1;
std::cout << e << "\n"; // will output "one"
}
之后,您可以添加一些自己的精美操纵器,而不是直接使用 std::ios_base::iword。像这样:
inline std::ios_base& format_my_enum_as_int(std::ios_base& ib)
{
ib.iword(getxalloc()) = 0;
return ib;
}
inline std::ios_base& format_my_enum_as_string(std::ios_base& ib)
{
ib.iword(getxalloc()) = 1;
return ib;
}
int main()
{
my_enum e = one;
std::cout << format_my_enum_as_int << e << "\n"; // will output "1"
std::cout << format_my_enum_as_string << e << "\n"; // will output "one"
}
【讨论】:
这个解决方案远非完美;但是对于您的问题没有真正好的解决方案。
class MyClass {...};
namespace xml
{
std::ostream& operator << (std::ostream& os, MyClass& c);
}
namespace text
{
std::ostream& operator << (std::ostream& os, MyClass& c);
}
如您所见,我将流运算符放在命名空间中。因此,我必须将命名空间包含在当前命名空间中。这只需简单的 using 声明即可完成。
using namespace xml;
诀窍是将 using 声明放在尽可能小的范围内。
【讨论】: