多个输出运算符?

发布于 2024-08-07 06:47:59 字数 184 浏览 5 评论 0原文

是否可以为枚举定义多个输出运算符?我想使用这个

std::ostream& operator<< (std::ostream& os, my_enum e);

运算符来(1)打印人类可读的文本并(2)将其转换为一些代码以存储在数据库中。

谢谢

is it possible to define multiple output operators for an enum? I want to use this

std::ostream& operator<< (std::ostream& os, my_enum e);

operator to (1) print a human readable text and to (2) convert it to some code for storing in a database.

Thanks

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

踏雪无痕 2024-08-14 06:47:59

创建将返回一些对象而不是 ostream& 的包装器它将处理打印。在您的情况下,它将对象打印人类可读的值和对象打印数据库代码。这是打印人类可读形式和整数形式的粗略示例。 ostream_enum_wrapper_ human 类及其运算符 <<用于打印人类可读的形式,类 ostream_enum_wrapper_int 及其 <<用于打印整数代码。从 ostream& 切换对于包装器,运算符 <<使用 (ostream&,wrappertag),它将 ostream 对象包装在包装器内部并返回包装对象。那么接下来<<运算符在包装器对象上调用,而不是在 ostream& 上调用,并且包装器类知道如何打印值。

#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;
}

打印 00two

Create wrappers which will return some object instead of ostream& which will handle printing. In your case it will object for printing humand-readable value and object for printing database code. Here's rough example which prints human-readable form and integer form. ostream_enum_wrapper_human class with its operator << is used for printing human-readable form, class ostream_enum_wrapper_int with its << is used for printing integer code. To switch from ostream& to wrapper, operator << (ostream&, wrappertag) is used, which wraps ostream object inside of wrapper and returns wrapped object. So next << operator is called on wrapper object, not on ostream&, and wrapper class knows how to print value.

#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;
}

prints zero0two

回忆那么伤 2024-08-14 06:47:59

您可以利用第一个参数的重载。

//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);  }

You may take advantage of overloading by the first argument.

//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) {};
};

Then write stream modifier that converts the stream to wrapping databasefmt class, so that next output to that modified stream would be database output for you enum. The printing code would look like this:

output_stream << "DATA: "<< database_format << my_enum::Value << "END OF DATA" ;
// Type:   std::ostream   |   databasefmt   |            std::ostream          |

and the wrapper like this:

//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);  }
べ繥欢鉨o。 2024-08-14 06:47:59

当然为什么不呢?您必须创建一个ostream 派生类来实现写入数据库,与ofstream 写入文件非常相似。魔鬼在于细节。

Sure why not? You would have to create an ostream derived class which implements writing to the database, much the same as ofstream writes to a file. The devil is in the details.

陈独秀 2024-08-14 06:47:59

首选方法是使用 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"
}

The preferred way is to use std::ios_base::xalloc and then 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"
}

After that you could add some fancy manipulator of your own, instead of using std::ios_base::iword directly. Like this:

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"
}
呆萌少年 2024-08-14 06:47:59

这个解决方案远非完美;但对于你的问题,没有一个真正好的解决方案。

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 声明放在尽可能小的范围内。

This solution is far from perfect; but there is no really nice one to your problem.

class MyClass {...};

namespace xml
{
    std::ostream& operator << (std::ostream& os, MyClass& c);
}

namespace text
{
    std::ostream& operator << (std::ostream& os, MyClass& c);
}

As you can see I put the stream operators in namespaces. As a result I have to include the namespace into the current one. This is simply done with a simple using declaration.

using namespace xml;

The trick is to put the using declaration in the smalest scope possible.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文