Home > Software design >  is there a null stream? optional printing
is there a null stream? optional printing

Time:10-05

I use functions like

void doStuff(type thing, bool print = false, std::ostream& S = std::cout)
{
    thing  ;
    if(print)
        S << "new thing: " << thing << '\n';
}

so that I can use the same function and decide on call if I want it to print documentation of what is happening and if I wish I can print that on seperate streams -I don't know if I can even do that with std::ostream-

I now believe that it will be better to do

void doStuff(type thing, std::ostream& S = NULL)
{
    thing  ;
    if(S)
        S << "new thing: " << thing << '\n';
}

but that doesn't work as std::ostream doesn't accept NULL

questions:
-is there some kind of constant of the stream type that stops the if condition?
-can I use a different type of stream that is more flexible to accept streams like string streams and file streams?
-is there a better way to handle flexible documentation?

CodePudding user response:

You can use the Null sink of the boost::iostream library.

Here is a working example:

#include <iostream>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/device/null.hpp>

boost::iostreams::stream<boost::iostreams::null_sink> nullstream{boost::iostreams::null_sink()};

void print_to_stream(std::ostream& s = nullstream)
{
  s << "hello" << std::endl;
}

int main()
{
  std::cout << "calling print_to_stream with s = std::cout" << std::endl;
  print_to_stream(std::cout);
  std::cout << "calling print_to_stream without argument" << std::endl;
  print_to_stream();

  return 0;
}

You may want to hide the variable nullstream inside some namespace or classs.

CodePudding user response:

Writing own streams is not difficult and can be found in good books.

I created a "NULL" stream class for you.

Please see the very simple example below.

#include <iostream>

// This is a stream which does not output anything
class NullStream : public std::ostream
{
    // streambuffer doing nothing
    class NullBuffer : public std::streambuf
    {
    public:
        int overflow(int c) noexcept override { return c; }
    } nullBuffer;

public:
#pragma warning(suppress: 26455)
    NullStream() : std::ostream(&nullBuffer) {}
    NullStream(const NullStream&) = delete;
    NullStream& operator=(const NullStream&) = delete;
};


// Define a global null stream
NullStream nout;

void doStuff(int& i, std::ostream& stream = nout)
{
    i  ;
    stream << i << '\n';
}

int main() {

    int i{};
    doStuff(i, std::cout);
    doStuff(i, std::cout);
    doStuff(i, std::cout);
    doStuff(i);
    doStuff(i);
    doStuff(i);
    doStuff(i, std::cout);
}

CodePudding user response:

Instead of using an ofstream reference, use a pointer so that you can accept a nullptr. The reason why you can't pass NULL is because references can't reference NULL because it may lead to dangerous undefined behavior like core dumping, segfaults, disk reformatting, etc.

Do something like this:

void doStuff(type thing, std::ostream* S = nullptr)
{
    thing  ;
    if(S != nullptr)
        (*S) << "new thing: " << thing << '\n';
}

This is a bit safer and can accept a nullptr.

Overall, if you are just outputting either to a file or console, ofstream seems to be the way. On the flexible doc side, I wouldn't really have a problem doing it like this. I may just have a logging class and use that to do warnings, info logs, saving to files, etc.

CodePudding user response:

As mentioned in my comment, a possible solution could be to use simple function overloading.

// Function for not printing anything
void doStuff(type& thing)
{
    thing  ;
}

// Function for printing things
void doStuff(type thing, std::ostream& S)
{
    // Do the common things first
    doStuff(thing);

    // And then print
    S << "new thing: " << thing << '\n';
}
  • Related