I'm trying to createa function that takes command line arguments, parses them, and returns a stream to be used for output. If a filename is specified, the program will write to that file. If no filename is specified, the default output will be to cout.

I haven't gotten to the parsing yet. Simply passing an ostream parameter and trying to assign it to equal cout is giving me preoblems already. The error is one of those really long errors, so I won't post it unless someone wants it. I've tried making line 15 either an ostream or an ofstream. Neither works.

#include <ostream>
#include <fstream>
#include <iostream>
using namespace std;


void foo(ostream& outs)
{
    outs = cout;
}


int main()
{
    ofstream outs;
    foo(outs);
    outs << "Hello World\n";
    return 0;
}

Recommended Answers

All 5 Replies

You cannot do what you are trying to do because objects in C++ are not references, they are objects. When you create the outs object in main(), you create an object, not a reference to another object, so you cannot "re-seat" it by making it refer to something else (in particular, std::cout). One simple way to achieve what you are trying to achieve is to do the following:

#include <ostream>
#include <fstream>
#include <iostream>

std::ostream& global_out(std::ostream& outs = std::cout)
{
    static std::ostream& gbl_out = outs;
    return gbl_out;
}

// if you want to assign all outputs to std::cerr, you do:
int main()
{
    global_out(std::cerr);

    global_out() << "Hello World\n";

    return 0;
}

// if you want to assign all outputs to std::cout, you do nothing:
int main() 
{
    global_out() << "Hello World\n";

    return 0;
}

// if you want to assign all outputs to a file, you do:
int main() 
{
    std::ofstream file_out("my_program.log");
    global_out(file_out);

    global_out() << "Hello World\n";

    return 0;
};

That's one simple way to do things, it is not super-robust, of course, you should implement the global-out as a proper singleton implementation, but you get the idea. And, technically, outputs that would occur after main has finished would be unsafe, but that's always the case anyways.

Wait.. you want to redirect cout to your stream?
Or are you trying to redirect your output to the console?

cout itself is a stream to the console. You can't just assign it like that. What about using std::streambuf and cout.rdbuf()?

OK, here's what I'd like to do. See the program below. It doesn't compile, but goes a little further than the last one I posted.

#include <ostream>
#include <fstream>
#include <iostream>
using namespace std;



void set_output_stream(int argc, char* argv[], ostream& outs)
{
    // if there are any arguments, assume the first argument is the output
    // filename and try to open it.

    if(argc > 1)
    {
        outs.open(argv[1]);
    }
    else
    {
        // no arguments, so use cout
        outs = cout;
    }
}


void HelloWorld(ostream& outs)
{
    outs << "Hello World\n";
}


int main(int argc, char* argv[])
{
    ofstream outs;
    set_output_stream(argc, argv, outs);
    HelloWorld(outs);
    return 0;
}

Now here's one that DOES work, but does not parse any arguments. However, it does pass an ostream parameter to a function and the function writes either to the screen and to a file. I want to pass a stream to function and have the function write to it.

#include <ostream>
#include <fstream>
#include <iostream>
using namespace std;


void HelloWorld(ostream& outs)
{
    outs << "Hello World\n";
}


int main(int argc, char* argv[])
{
    HelloWorld(cout);
    ofstream outs;
    outs.open("HelloWorld.txt");
    HelloWorld(outs);
    outs.close();
    return 0;
}

Mike, for the moment, I'm only planning on having one ofstream object and these are fairly simple programs, so making it global would work in this particular case. It just doesn't seem to sit right, though. What if I have more than one stream for whatever reason? Can I not have a function set the where the output goes without changing everything else?

The easiest thing in this case is to just use a smart pointer, as so:

#include <ostream>
#include <fstream>
#include <iostream>
#include <memory>
using namespace std;

// a custom deleter that does nothing (no sure why the standard library doesn't have one of these):
struct null_deleter {
  template <typename T>
  void operator()(T*) const noexcept { };
};


shared_ptr<ostream> set_output_stream(int argc, char* argv[])
{
    // if there are any arguments, assume the first argument is the output
    // filename and try to open it.

    if(argc > 1)
    {
        return shared_ptr<ostream>(new ofstream(argv[1]));
    }
    else
    {
        // no arguments, so use cout (with no deleter)
        return shared_ptr<ostream>(&cout, null_deleter());
    }
}


void HelloWorld(ostream& outs)
{
    outs << "Hello World\n";
}


int main(int argc, char* argv[])
{
    shared_ptr<ostream> outs = set_output_stream(argc, argv);
    HelloWorld(*outs);
    return 0;
}

If you don't have a C++11 capable compiler, just use a boost::shared_ptr instead (or std::tr1::shared_ptr).

Great. Thank you!

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.