简体   繁体   English

多输出运算符?

[英]Multiple output operators?

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. 操作者(1)打印人类可读文本并(2)将其转换为某些代码以存储在数据库中。

Thanks 谢谢

Create wrappers which will return some object instead of ostream& which will handle printing. 创建包装器,它将返回一些对象而不是ostream,它将处理打印。 In your case it will object for printing humand-readable value and object for printing database code. 在您的情况下,它将反对打印humand可读的值和对象以打印数据库代码。 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. ostream_enum_wrapper_human类及其运算符<<用于打印人类可读的形式,类ostream_enum_wrapper_int及其<<用于打印整数代码。 To switch from ostream& to wrapper, operator << (ostream&, wrappertag) is used, which wraps ostream object inside of wrapper and returns wrapped object. 要从ostream转换为包装器,使用operator <<(ostream&,wrappertag),它将ostream对象包装在包装器内并返回包装对象。 So next << operator is called on wrapper object, not on ostream&, and wrapper class knows how to print value. 所以下一个<<运算符是在包装器对象上调用的,而不是在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;
}

prints zero0two 打印零0两

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. 然后编写流修改器,将流转换为包装databasefmt类,以便下一个输出到该修改后的流将为您枚举的数据库输出。 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);  }

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. 你必须创建一个ostream派生类,它实现写入数据库,就像同样ofstream写入文件。 The devil is in the details. 细节决定成败。

The preferred way is to use std::ios_base::xalloc and then std::ios_base::iword: 首选方法是使用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"
}

After that you could add some fancy manipulator of your own, instead of using std::ios_base::iword directly. 之后你可以添加一些你自己的花哨操纵器,而不是直接使用std :: ios_base :: iword。 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"
}

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. 诀窍是将使用声明置于最小范围内。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM