C++ 使用std::streams格式化输出

C++ 使用std::streams格式化输出,c++,format,stream,std,C++,Format,Stream,Std,我有一个对象,我想能够流。但是我希望能够通过使用不同的格式以不同的方式对其进行流式处理,或者我应该说是描述这个对象的方式。我想知道如何用流来解决这个问题 我想要的是能够使用通用格式,并使用某种格式适配器将通用格式转换为首选格式 我还希望能够将格式与项的实现分开,这样我就不必在每次添加或更改新格式时都更改项 这段代码大致说明了我想要什么 Item item; std::cout << "generic formatted:" << item; std::cout <&

我有一个对象,我想能够流。但是我希望能够通过使用不同的格式以不同的方式对其进行流式处理,或者我应该说是描述这个对象的方式。我想知道如何用流来解决这个问题

我想要的是能够使用通用格式,并使用某种格式适配器将通用格式转换为首选格式

我还希望能够将格式与项的实现分开,这样我就不必在每次添加或更改新格式时都更改项

这段代码大致说明了我想要什么

Item item;
std::cout << "generic formatted:" << item;
std::cout << "custom formatted:" << CustomItemFormat() << item;
项目;

是的,这是可能的,你正在寻找的神奇词汇是流


查看此问题:

Item.CustomItemFormat()有什么不好的地方

或者有一些设计模式旨在解决这个问题,即访问者模式

您还可以使用CustomItemFormat(项目)


我不认为让streams解决这个问题是正确的方向,您应该将显示自己的任务委托给Item类

您需要编写一个流操纵器,它将信息存储在流中,然后由
操作符使用我越想它,我就开始怀疑我是否以错误的方式来处理它。也许我应该有一个通用的格式接口,并设置项目的格式,这样项目就可以使用这种格式输出自己


这有意义吗?

我个人会编写一套格式化程序。
格式化程序必须知道要格式化的对象的内部结构 但与他们交朋友应该不是什么大事

class X
{ friend std::ostream& operator<<(std::ostream& str,XML_Format const& formatter);
  friend std::ostream& operator<<(std::ostream& str,Json_Format const& formatter);
  friend std::ostream& operator<<(std::ostream& str,Fred_Format const& formatter);
  public: int value() const {return 5;}
};
struct XML__Foram   { X const& print; XML_Format(X const& v):   print(v) {} };
struct Json_Format  { X const& print; Json_Format(X const& v):  print(v) {} };
struct Fred_Format  { X const& print; Fred_Format(X const& v):  print(v) {} };

std::ostream& operator<<(std::ostream& str,XML_Format const& formatter)
{
     return str << "<XObj>" << formatter.print.value() << "</XObj>";
}
std::ostream& operator<<(std::ostream& str,Json_Format const& formatter)
{
     return str << "{XObj:{" << formatter.print.value() << "}}";
}
std::ostream& operator<<(std::ostream& str,Fred_Format const& formatter)
{
     return str << "Killl Kill Kill. Friday 13th";
}

int main()
{
     X   obj;
     std::cout << XML_Format(obj) << std::endl;
}
X类
{friend std::ostream&operator尝试使用访问者设计模式:

struct Object_Writer_Interface
{
  virtual void write_member_i(int value) = 0;
  virtual void write_member_c(char value) = 0;
};

struct Object
{
    int i;
    char c;
    void write(Object_Writer_Interface * p_writer)
    {
        if (p_writer)
        {
            p_writer->write_member_i(i);
            p_writer->write_member_c(c);
        }
    }
};

struct Stream_Object_Writer
  : public Object_Writer_Interface
{
    Stream_Object_Writer(std::ostream& out)
       : m_out(out)
       { ; }
    void write_member_i(int value)
    {
        m_out << i << '\n';
    }
    void write_member_c(char c)
    {
        m_out << "'" << c << "'\n";
    }
    std::ostream& m_out;
};


int main(void)
{
    Object  o;
    o.i = 5;
    o.c = 'M';

    // Create a writer for std::cout
    Stream_Object_Writer writer(std::cout);

    // Write the object to std::cout using the writer
    o.write(&writer);

    return EXIT_SUCCESS;
}
struct Object\u Writer\u接口
{
虚空写入成员i(int值)=0;
虚空写入成员(字符值)=0;
};
结构对象
{
int i;
字符c;
无效写入(对象写入器接口*p写入器)
{
如果(p_编写器)
{
p_writer->write_member_i(i);
p_writer->write_member_c(c);
}
}
};
结构流\u对象\u写入程序
:公共对象\写入程序\接口
{
流\u对象\u写入程序(std::ostream&out)
:m_out(out)
{ ; }
无效写入成员(int值)
{

m_outIOStreams不太适合这种情况,但您可以使用提供更好扩展性的格式库。例如:

struct Item {
  int value;
};

template <>
struct fmt::formatter<Item> {
  enum format { generic, custom };
  format f = generic;

  constexpr auto parse(parse_context &ctx) {
    auto it = ctx.begin(), end = ctx.end();
    if (it == end) return it;
    if (*it == 'g') f = generic;
    else if (*it == 'c') f = custom;
    else return it;
    return ++it;
  }

  template <typename FormatContext>
  auto format(const Item& item, FormatContext &ctx) {
    return format_to(ctx.out(), f == generic ? "{}" : "{:x}", item.value);
  }
};

免责声明:我是{fmt}的作者.

项目应该能够显示自己,但不必知道其格式。这意味着每次新的格式出现时,项目都必须更改。可以使用装饰图案,尽管在处理许多项目或其他类型的项目时,也使用给定的格式会有点不切实际。如何使用装饰图案d如果一个项目不知道以哪种格式显示它自己,它就能够显示它自己?如上所述,访问者模式应该解决这个问题。只要它知道显示什么,它就不需要知道任何关于格式的信息。我知道流操纵器,但不知道它们如何为我解决这个问题。我将不得不看看这种方法。看起来这样做是可能的,但在我看来,我的问题不应该像这样解决。更重要的是操纵流本身,而不是对象的输出。也许装饰器是正确的方法来做这件事……这里的问题是项(或项的流操作符)必须了解所有格式。我想将格式与项目分开,因为我知道项目有很多不同的格式,但我不知道必须使用哪种格式。增加了将格式与项目类分开的要求。是的,这几乎就是我所想的。我不喜欢fo之间的强耦合但是,rmat和对象。它希望在不必更改格式的情况下更改需要格式的类的实现。与使用自定义格式设置程序和使用
friend
不同,我使用
Visitor
模式并创建自定义编写器。因此,无需添加新的
操作符@Thomas:Iys 6我的方法写了一个新的流操作符。你的方法写了一个新的写器接口。耦合是一样的。看起来另一个Java开发人员正试图写C++@Martin York,你能详细说明一下这个评论吗。你对这个解决方案有什么不同意见吗?我只说它看起来像是这个问题的Java解决方案(1,它不是C++)。两个问题。因为它不是C++,所以很难与库集成,尝试和C++一样(STL,Boost跳到头脑)。2)对象和对象的接口紧密耦合。对对象的实现的任何改变都需要接口和所有依赖项被重写。@ Martin York,为什么这不是C++?这是一个标准的实现,我在学习java之前已经实现了它。在我的实现中,所有的T都是这样的。在我所研究的实现中,编写器的更改比对象的更改更频繁。当向对象添加成员时,
操作符尝试将此方法用于任何标准算法。例如std::copy,使用std::istream\u迭代器或STL中发生的任何其他事情。
fmt::print("{}", Item{42}); // Default generic format - value formatted as decimal
fmt::print("{:g}", Item{42}); // Explicit generic format
fmt::print("{:c}", Item{42}); // Custom format - value formatted as hex