3

I want to declare a function which writes to std::out by default, but also optionally enables writing to another output stream, if any is provided. For example:

print_function(std::string & str, 
               std::ostream & out = std::cout, 
               std::ostream & other = nullptr) // <-- how to make it optional???
{
    out << str;
    if (other == something) // if optional 'other' argument is provided
    {
        other << str;
    }
}

Setting nullprt obviously does not work, but how can this be done?

Stingery
  • 432
  • 4
  • 16
  • Related: http://stackoverflow.com/questions/11826554/standard-no-op-output-stream – lorro Jun 30 '16 at 11:32
  • 2
    It looks to me like it would be much more natural to have two overloads, one with two arguments, and one with three arguments. –  Jun 30 '16 at 11:36
  • 1
    @Hurkyl: or keeping the one with 2 argument and passing a "`tee_stream`". – Jarod42 Jun 30 '16 at 11:39
  • Having a stream swallowing the input (as in the accepting answer of http://stackoverflow.com/questions/11826554/standard-no-op-output-stream) is a terrible solution, here. –  Jun 30 '16 at 11:41

3 Answers3

7

with pointer, or boost::optional

void print_function(std::string & str, 
               std::ostream & out = std::cout, 
               std::ostream* other = nullptr)
{
    out << str;
    if (other)
    {
        *other << str;
    }
}

or

void print_function(std::string & str, 
               std::ostream & out = std::cout, 
               boost::optional<std::ostream&> other = boost::none)
{
    out << str;
    if (other)
    {
        *other << str;
    }
}
Jarod42
  • 203,559
  • 14
  • 181
  • 302
1

You can use boost::optional or pointer, as suggested by @Jarod42. However, both approaches force you to use conditional statements in the function body.

Here is another approach whose advantage is the simplicity of the function body:

 void print_function(std::string & str, 
              std::ostream & out = std::cout, 
              std::ostream& other = null_stream)
{
     out << str;
     other << str;  //no "if" required here.
 }

And here is how you may define null_stream object:

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

boost::iostreams::stream<boost::iostreams::null_sink> null_stream {
          boost::iostreams::null_sink{} 
};

Here null_stream is a std::ostream which does nothing. There are other ways to implement it as well.

Hope that helps.

Community
  • 1
  • 1
Nawaz
  • 353,942
  • 115
  • 666
  • 851
1

I'd simply use function overloading, rather than default arguments

// declare the functions in a header

void print_function(std::string &str);
void print_function(std::string &str, std::ostream &ostr);
void print_function(std::string &str, std::ostream &ostr, std::ostream &other);

// and in some compilation unit, define them

#include "the_header"

void print_function(std::string &str)
{
       print_function(str, std::cout);
}

void print_function(std::string &str, std::ostream &ostr)
{
     // whatever
}

void print_function(std::string & str, 
                    std::ostream &ostr, 
                    std::ostream &other)
{
    print_function(str, ostr);

    other << str;
}

All three versions of these functions can do anything you like. Depending on your needs, any can be implemented using the others.

If you need to interleave logic in the three functions (e.g. statements affecting other need to be interleaved with statements from one of the other functions) then introduce helper functions to implement the logic in separate, more granular, parts.

Peter
  • 35,646
  • 4
  • 32
  • 74