输出到几个ostreams的类(文件和控制台) [英] Class to output to several ostreams (file and console)

查看:184
本文介绍了输出到几个ostreams的类(文件和控制台)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是的,我甚至不确定如何正确地制定这个;我觉得这是一个涉及的问题。我确定有人可以帮助我。但

Right, I'm not even sure how to correctly formulate this; I feel it's a bit of an involved question. I'm sure someone can help me out here though.

这就是我想要做的事情:

This is what I want to do:


  1. 有一个我可以发送内容的课程,就像这样。

  1. Have a single class that I can send stuff to, like this.

icl << "Blah blah blah" << std::endl;


  • 我希望能够继承std :: basic_ostream的.attach()类它。

  • I want to be able to .attach() classes that inherit std::basic_ostream to it.

    这些类可以按照自己的方式格式化输出。有人可能会添加一个时间戳并写入日志,另一个可能会将其写入控制台,另一个可能会在游戏中显示它。

    Those classes would then be able to format the output their own way. One might add a timestamp and write to a log, the other might write it to the console, the other might display it in-game.

    有人想让我开始朝着正确的方向前进吗?这是我几乎有的想法。

    Anyone care to get me started in the right direction? Here's the idea I pretty much have.

    #include <vector>
    
    class OutputMan {
        std::vector<std::basic_ostream&> m_Streams;
    
    public:
        void attach(std::basic_ostream& os) {
            m_Streams.push_back(os);
        }
    }
    

    问题#1:我需要继承和覆盖什么来发送

    Question #1: What do I need to inherit and override to send

    icl << "Blah!" << std::endl;
    

    到m_Streams中的每个流?

    To every stream in m_Streams?

    问题2:如何继承std :: basic_ostream并创建一个更改输出的类,例如,在其开头添加时间戳?我也希望这个类输出到一个文件。

    Question #2: How do I inherit std::basic_ostream and create a class that changes the output to, for example, add a timestamp to the start of it? I also want for this class to output to a file.

    推荐答案

    我想我的做法有点不同。我可能已经做了一些比必要更精细的事情 - 我担心我可能会因为尝试使用新的C ++ 11功能而感到沮丧。无论如何,使用代码:

    I think I'd do things a bit differently. I've probably made this just a bit more elaborate than necessary -- I'm afraid I may have gotten a little carried away with trying to put new C++11 features to good use. Anyway, on with the code:

    #include <streambuf>
    #include <fstream>
    #include <vector>
    #include <iostream>
    #include <initializer_list>
    
    namespace multi { 
    class buf: public std::streambuf {
        std::vector<std::streambuf *> buffers;
    public:
        typedef std::char_traits<char> traits_type;
        typedef traits_type::int_type  int_type;
    
        buf(std::vector<std::ofstream> &buf) {
            for (std::ofstream &os : buf)
                buffers.push_back(os.rdbuf());
        }
    
        void attach(std::streambuf *b) { buffers.push_back(b); }
    
        int_type overflow(int_type c) {
            bool eof = false;
            for (std::streambuf *buf : buffers) 
                eof |= (buf -> sputc(c) == traits_type::eof());
            return eof ? traits_type::eof() : c;
        }   
    };
    
    class stream : public std::ostream { 
        std::vector<std::ofstream> streams;
        buf outputs;
    public:   
        stream(std::initializer_list<std::string> names)
            : streams(names.begin(), names.end()), 
              outputs(streams), 
              std::ostream(&outputs) 
        { }
        void attach(std::ostream &b) {
            outputs.attach(b.rdbuf());
        }
    };
    }
    
    int main() { 
        multi::stream icl({"c:\\out1.txt", "c:\\out2.txt"});
        icl.attach(std::cout);
    
        icl << "Blah blah blah" << std::endl;
    }
    

    正如你所看到的,这已经接受了操纵器(它应该与任何操纵器,而不仅仅是 std :: endl )。如果要写入多个文件(可以/可以作为fstream打开的东西),您可以根据需要在构造函数中指定尽可能多的名称(当然,在系统强加的范围内)。对于 std :: cout std :: cerr 之类的东西,你不一定有文件名,您可以按照原定的目的使用附加

    As you can see, this already accepts manipulators (which should work with any manipulator, not just std::endl). If you want to write to multiple files (things that could/can be opened as fstreams) you can specify as many of those names in the constructor as you like (within the limits imposed by your system, of course). For things like std::cout and std::cerr for which you don't necessarily have a file name, you can use attach as you originally intended.

    我想我应该补充一点,我对此并不满意这个原样。这需要一些相当严肃的重写,但经过一些思考,我认为正确的方式可能是 multi :: stream 的ctor是改为使用可变参数模板,因此您可以执行以下操作: multi :: stream icl(c:\\out1.txt,std :: cout); ,它将根据其类型理清如何使用每个参数。我可以更新这个答案以便很快包含该功能。

    I suppose I should add that I'm not entirely happy with this as-is. It'd take some fairly serious rewriting to do it, but after some thought, I think the "right" way would probably be for multi::stream's ctor to be a variadic template instead, so you'd be able to do something like: multi::stream icl("c:\\out1.txt", std::cout);, and it would sort out how to use each parameter based on its type. I may update this answer to include that capability some time soon.

    就第二个问题而言,我写了另一个答案涵盖了基本的想法,但可能有点过于精细,所以你关心的部分可能有点得到可以这么说,在shuffle中丢失了 - 它有很多逻辑来处理你并不真正关心的行长度(但确实产生了具有指定前缀的每个输出行,就像你想要的那样)。

    As far as the second question goes, I've written another answer that covers the basic idea, but is probably a bit overly elaborate, so the part you care about may kind of get lost in the shuffle, so to speak -- it has quite a bit of logic to deal with line lengths that you don't really care about (but does produce each output line with a specified prefix, like you want).

    这篇关于输出到几个ostreams的类(文件和控制台)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆