Question

For some reason, when I try to use std::endl with my OutputStream object, it prints '1' both on-screen and in the file!! (I think it is actually trying to print the OutputStream object itself, but I could be wrong.) Here is my code:

OutputStream.h

#ifndef OUTPUTSTREAM_H
#define OUTPUTSTREAM_H

#include <fstream>
#include <iostream>
#include <string>

class OutputStream : public std::ostream
{
    public:
        OutputStream(const std::string&);
        virtual ~OutputStream();
        //template <typename T> OutputStream& operator<<(T);
        template <typename T> OutputStream& operator<<(T& data)
        {
            std::cout << data;
            *(this->file) << data;
            return *this;
        }
        template <typename T> OutputStream& operator<<(const T& data)
        {
            std::cout << data;
            *(this->file) << data;
            return *this;
        }
        void changeDestinationTo(const std::string&);
        std::string getDestination() const;
        // overloading the endl operator to allow for the same functionality that exists on other ostream objects, and returning
        //  the same type allows for cascading calls
        static OutputStream& endl(OutputStream&);
    protected:
    private:
        std::string filename;
        std::ofstream * file;
};

#endif // OUTPUTSTREAM_H

OutputStream.cpp

#include "OutputStream.h"

#include <iostream>
#include <fstream>
#include <new>
#include <string>

OutputStream::OutputStream(const std::string& theFileName)
{
    // specify the filename
    this->filename = theFileName;
    // open the fileName with that file
    this->file = new(std::nothrow) std::ofstream(this->filename.c_str());
}

OutputStream::~OutputStream()
{
    // delete the file! (no, not really)
    this->file->close();
    delete this->file;
}

/*template <typename T>
OutputStream& OutputStream::operator<<(T)
{
    std::cout << data;
    *(this->file) << data;
    return *this;
}

template <typename T>
OutputStream& OutputStream::operator<<(T& data)
{
    std::cout << data;
    *(this->file) << data;
    return *this;
}

// the const-correct version of the above function
template <typename T>
OutputStream& OutputStream::operator<<(const T& data)
{
    // writing the data to std::cout
    std::cout << data;
    // writing the data to the file that we specify
    *(this->file) << data;
    return *this;
}
*/
void OutputStream::changeDestinationTo(const std::string& newFileName)
{
    // close the currently-open file
    this->file->close();
    // open up the file at newFileName
    this->filename = newFileName;
    this->file->open(newFileName.c_str());
}

std::string OutputStream::getDestination() const { return this->filename; }

OutputStream& OutputStream::endl(OutputStream& myStream)
{
    // call std::endl on both std::cout and *(this->file)
    std::cout << std::endl;
    *(myStream.file) << std::endl;
    // allow for cascading by returning myStream
    return myStream;
}

main.cpp

#include "Array.h"
#include "OutputStream.h"

#include <iostream>

using namespace std;

int main()
{
    // setup the OutputStream
    OutputStream outputter("file.txt");
    // do some stuff with it
    outputter << "This is a test to make sure that it works.\n";
    outputter << "25 + 3.7 == " << 25 + 3.7 << '\n'; // doesn't print '1'
    outputter << "\nNow testing this with objects:\n" << OutputStream::endl; // prints '1'
    // declare an Array of 10 ints
    Array<int> someArray(10);
    // output them
    outputter << "Printing an Array:\n";
    outputter << someArray << OutputStream::endl;
    return 0;
}

Is there any way to readily remedy this?? (I have tried declaring a friend std::ostream& operator<<(std::ostream& standardStream, const OutputStream& myOutputStream) { return standardStream; } but that did NOTHING to solve the problem...

Was it helpful?

Solution

I believe you need to create an overload for function pointers (manipulators) like this:

template<typename T>
OutputStream& operator<<(std::ostream& (*manip)(std::ostream&))
{
    manip(*this->file);
    manip(std::cout);

    return *this;
}

OTHER TIPS

I was trying to pass a function pointer (endl) to operator<<. That is, I was trying to "print" a function pointer (an address). It worked because I have defined that function to do its job.

Try overloading the operator<< to accept pointers to methods as an argument.

A second option is to create a new class within OutputStream called (for example) endl (similar to the way done to define class specific exceptions) like so:

class endl{}

after that all you need to do is to make operator<< support this type of class:

 OutputStream& operator<<(OutputStream::endl& endl){
    cout << endl;
    *flie << endl;
    return *this;
    }

and using it like this:

outputer << "some string" << endl();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top