trying to write std:out and file at the same time

社会主义新天地 提交于 2019-12-01 06:47:32

问题


I am trying to write to file and stdout at the same time within c++ by overloading ofstream

test.h

 #pragma once 

#include <iostream>

using  std::ofstream;

class OutputAndConsole:public ofstream
{
public:
    std::string fileName;        
    OutputAndConsole(const std::string& fileName):ofstream(fileName),fileName(fileName){
    };
    template <typename T>
    OutputAndConsole& operator<<(T var);
};


template <typename T>
OutputAndConsole& OutputAndConsole::operator<<(T var)
{
    std::cout << var;
    ofstream::operator << (var);
    return (*this);
};

test.cpp

  OutputAndConsole file("output.txt");
  file << "test" ;

The output in the file is

01400930

but in the console is

test

I debugged the code it looks like it is entering into

_Myt& __CLR_OR_THIS_CALL operator<<(const void *_Val)

What am I doing wrong?


回答1:


The problem

ofstream::operator << (var);

It's your use of ofstream::operator<< as a qualified function call. You're mandating that the function lookup locate a member function of ofstream; the best match that's a member is the one for void*, whereas the specialisation for char* that prints the actual string contents is a free function (i.e. not a member function).

You'll find the same problem if you do this with cout, too:

std::cout.operator<<(var);

The solution

This might do it:

static_cast<ofstream&>(*this) << var;

because you're still using normal operator syntax (with all the overload resolution that this entails), but doing so with an ofstream as the LHS operand.

I haven't actually tested it, though.

Conclusion

As an aside, your operator<< ought to be a free function too, in order to fit in with this convention.

So:

struct OutputAndConsole : std::ofstream
{
    OutputAndConsole(const std::string& fileName)
       : std::ofstream(fileName)
       , fileName(fileName)
    {};

    const std::string fileName;
};

template <typename T>
OutputAndConsole& operator<<(OutputAndConsole& strm, const T& var)
{
    std::cout << var;
    static_cast<std::ofstream&>(strm) << var;
    return strm;
};

I also took the liberty of making some minor syntax adjustments.




回答2:


I'm not going to comment on why your approach doesn't work, mainly because it cannot be patched up to work properly. The main problem is that you can't use your stream an pass it to something which expected an std::ostream& and still write to both streams. However, there is a relatively simple although not necessarily obvious approach to implement what you actually want: You'd derive a new stream buffer, i.e., a class derived from std::streambuf, and override its overflow() and sync() functions. Here is the complete code for a simple demo:

#include <streambuf>

struct teebuf
    : std::streambuf
{
    std::streambuf* sb1_;
    std::streambuf* sb2_;

    teebuf(std::streambuf* sb1, std::streambuf* sb2)
        : sb1_(sb1), sb2_(sb2) {
    }
    int overflow(int c) {
        typedef std::streambuf::traits_type traits;
        bool rc(true);
        if (!traits::eq_int_type(traits::eof(), c)) {
            traits::eq_int_type(this->sb1_->sputc(c), traits::eof())
                && (rc = false);
            traits::eq_int_type(this->sb2_->sputc(c), traits::eof())
                && (rc = false);
        }
        return rc? traits::not_eof(c): traits::eof();
    }
    int sync() {
        bool rc(true);
        this->sb1_->pubsync() != -1 || (rc = false);
        this->sb2_->pubsync() != -1 || (rc = false);
        return rc? 0: -1;
    }
};

#include <fstream>
#include <iostream>

int main()
{
    std::ofstream fout("tee.txt");
    teebuf        sbuf(fout.rdbuf(), std::cout.rdbuf());
    std::ostream  out(&sbuf);
    out << "hello, world!\n";
}

Obviously, the creation of tee-stream could be packaged up nicely but how this looks exactly doesn't really matter. The important thing is that it is possible to create a custom destination (or source) for IOStreams and that it does not involve any attempt to inherit from std::ostream. The only reason to inherit from std::ostream (or std::istream) is to make the initialization of a stream with a custom stream buffer easier.



来源:https://stackoverflow.com/questions/13665090/trying-to-write-stdout-and-file-at-the-same-time

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!