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?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With