c++: Storing ostream in a List - c++

I have a function
foo(ostream& os)
which writes to the ostream passed to it.
I now want to write a test and therefore would like to store whatever is written by foo into a list.
What is a clean way of doing this?

Populate the list with a std::ostringstream instance:
#include <sstream>
#include <cassert>
void foo(std::ostream& out) { out << "test1"; } // example implementation
void test_foo()
{
std::ostringstream buffer;
foo(buffer);
assert(buffer.str() == "test1");
}

Related

Why pass input/output stream in a function?

Why would we want to do this:
#include <iostream>
void print(std::ostream& os) {
os << "Hi";
}
int main() {
print(std::cout);
return 0;
}
instead of this:
#include <iostream>
void print() {
std::cout << "Hi";
}
int main() {
print();
return 0;
}
Is there some certain advantage or functionality that is obtained only with the first version?
Yes, the first version is significantly better. Like already mentioned in the comments, it allows you to use any kind of std::ostream, not just std::cout. Some of the most important consequences of this architectural choice are:
You can use your function to print the required data to standard output, a file, a custom class written by your colleagues (e.g. database adapter, logger).
It is possible to test your void print function. E.g.:
TEST(MyFunctionShould, printHello)
{
std::string expectedResult("Hello");
std::ostringstream oss;
print(oss);
ASSERT_EQ(expectedResult, oss.str());
}

How do I display the contents of a std::vector of my own datatype and display the name on the console using std::copy?

I would like to display the contents of the std::vector<User> using std::copy in a similar way to how I've achieved it through std::for_each in the code below.
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
};
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
//How can I get std::copy to do what the std::for_each is doing?
std::copy(vectNames.begin(), vectNames.end(), std::ostream_iterator<User>(std::cout, "\n"));
//The following line is what I really would like std::copy to do.
std::for_each(vectNames.begin(), vectNames.end(), [](const User &user) {std::cout << user.GetName() << "\n"; });
}
You can simply overload the ostream operator:
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
void print(std::ostream& where) const
{ where << m_sName; }
};
/// Overloaded ostream operator
std::ostream& operator<< (std::ostream& out, const User& user)
{
user.print(out);
return out;
}
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
std::copy(vectNames.begin(), vectNames.end(), std::ostream_iterator<User>(std::cout, "\n"));
}
In general I always have an overloaded ostream as part of classes that store and output information.
Because of your comment I am a new programmer and am experimenting with different ideas, I'm posting this answer as an alternative approach which also shows some algorithm that you might enthusiastic about.
I think that std::copy isn't the right tool if what you want to do is both
calling a member function on the objects in a collection, and only after that
copying/printing them to screen
One, and maybe the best, approach is the one in the atru's answer, which basically solves only point 2 with std::copy (and this is something you already knew how to do it, based on your question), and point 1 by overloading <<, which makes the trick.
The alternative I propose is based on the idea that "calling a member function on every object of a collection" is actually a transform operation of that collection. std::transform, however, just like std::copy acts on iterators, not on ranges, so they cannot be easily composed with one another.
Here comes Boost, with boost::copy and boost::adaptors::transformed which allow you to do this:
boost::copy(
vectNames | transformed([](auto const& x){ return x.GetName(); }),
std::ostream_iterator<std::string>(std::cout, "\n")
);
where vectNames is "piped into" transformed, which applies the lambda on every element of the collection, resulting in a new temporary collection, which is the argument to boost::copy. If you were to use std::copy, you would have to store the temporary somewhere, e.g. in temp, before passing to std::copy its iterators temp.begin() and temp.end().
The full example is below. I hope it will give you some insight in different, more functional, approaches.
#include <functional>
#include <iostream>
#include <vector>
#include <string>
#include <boost/range/adaptor/transformed.hpp>
#include <boost/range/algorithm/copy.hpp>
class User {
private:
std::string m_sName;
public:
User(std::string sName):m_sName(sName) {}
std::string GetName()const {
return m_sName;
}
};
int main()
{
std::vector<User> vectNames;
vectNames.emplace_back("Jack");
vectNames.emplace_back("George");
vectNames.emplace_back("Jose");
using boost::adaptors::transformed;
boost::copy(
vectNames | transformed([](auto const& x){ return x.GetName(); }),
std::ostream_iterator<std::string>(std::cout, "\n")
);
}

regarding streams in c++

I want to use file streams and consol output stream. In constructor, I want to initialize with either file or consol output stream depending on parameter passed to constructor. Then I will have another function in class which will redirect output to that stream. what will be the code for it? I am trying with the below code which is not working.
Any other design suggestions are welcome.
class Test
{
private:
std::ios *obj;
std::ofstream file;
std::ostream cout1;
public:
// Test(){}
Test(char choice[])
{
if(choice=="file")
{
obj=new ofstream();
obj->open("temp.txt");
}
else
obj=new ostream();
}
void printarray()
{
for(int i=0;i<5;i++)
(*obj)<<"\n \n"<<"HI"
}
};
Something like this should work:
#include <iostream>
#include <fstream>
#include <string>
class Test
{
private:
std::ofstream file;
std::ostream& obj;
public:
// Use overloaded constructors. When the default constructor is used,
// use std::cout. When the constructor with string is used, use the argument
// as the file to write to.
Test() : obj(std::cout) {}
Test(std::string const& f) : file(f.c_str()), obj(file) {}
void printarray()
{
for(int i=0;i<5;i++)
obj<<"\n " << "HI" << " \n";
}
};
int main()
{
Test a;
a.printarray();
Test b("out.txt");
b.printarray();
}
PS Look at the changes to printarray. What you were trying, with %s, is good for the printf family of functions but not for std::ostream.
Any other design suggestions are welcome.
Two of these members are useless:
std::ios *obj;
std::ofstream file;
std::ostream cout1;
You can't do anything with a std::ios, a std::ostream that isn't associated with a streambuf is useless, and you never use file or cout1 anyway!
You want:
std::ofstream file;
std::ostream& out;
as shown in R Sahu's answer, and write to out.
Test(char choice[])
{
if(choice=="file")
This doesn't work, you need to use strcmp to compare char strings. You should probably use std::string not char*.

Proper way to create ostream to file or cout

I am trying to create a Log class for my project at school. It needs to either be able to write information to the stdout or to a file depending on the parameters it is passed. I was looking into how to do this and I stumbled upon a thread with a similar question here: Obtain a std::ostream either from std::cout or std::ofstream(file)
The only difference between this thread and my own is that I want to do it inside of a class. Looking at the solution though they use std::ostream out(buf) and construct the ostream on the fly with buf. How can i declare this properly in my Log class to be able to construct the "out" object only once i enter my Log constructor?
I took a quick stab at it below but I am not sure if it is correct or if I am on the right track. Appreciate any help, thanks.
EDIT: I want to be able to do out << "Some string" << endl; after i get this Log class working properly.
EDIT2: An error I am now receiving with the new code below error : 'std::basic_ostream<_CharT, _Traits>::basic_ostream() [with _CharT = char, _Traits = std::char_traits<char>]' is protected
// log.h
#include <string>
#include <fstream>
#ifndef LOG_H_
#define LOG_H_
class Log
{
public:
enum Mode { STDOUT, FILE };
// Needed by default
Log(const char *file = NULL);
~Log();
// Writing methods
void write(char *);
void write(std::string);
private:
Mode mode;
std::streambuf *buf;
std::ofstream of;
std::ostream out;
};
#endif
// log.cpp
#include "log.h"
#include <iostream>
#include <stdlib.h>
#include <time.h>
Log::Log(const char *file)
{
if (file != NULL)
{
of.open(file);
buf = of.rdbuf();
mode = FILE;
}
else
{
buf = std::cout.rdbuf();
mode = STDOUT;
}
// Attach to out
out.rdbuf(buf);
}
Log::~Log()
{
if (mode == FILE)
of.close();
}
void Log::write(std::string s)
{
out << s << std::endl;
}
void Log::write(char *s)
{
out << s << std::endl;
}
You create tmp with std::ostream tmp(buf); and store the address of it in out with this->out = &tmp;. However, tmp will go out of scope at the end of the constructor and the pointer will no longer be pointing at a valid object.
What you should do instead is make out not a std::ostream* but simply a std::ostream:
std::ostream out;
Then in your constructor, once you've got the buf ready, you can give it to out by doing out.rdbuf(buf);.
Response to edit:
The std::ostream doesn't have a default constructor - it has to take a buffer pointer. My mistake. However, the fix is simple. Use your constructor's member initialization list to pass a null pointer (nullptr in C++11, 0 or NULL in C++03):
Log::Log(const char *file)
: out(nullptr)
{
// ...
}

How do I change a C++ output stream to refer to cout?

I have a class that I want to give an output stream as a member to, to wit:
class GameBase {
protected:
ofstream m_OutputWriter;
...
}
There is a method in this class that takes a string argument and opens m_OutputWriter to point to that file, so data may be output to that file by using the standard << operator;
However, what I would like is to make the stream point to cout by default, so that if the output path is not specified, output goes to the console output instead of to a file, and it will be completely transparent by the calling class, who would use
m_OutputWriter << data << endl;
to output the data to the predetermined destination. Yet, I have tried a couple of the other examples here, and none of them exactly seem to fit what I'm trying to do.
What am I missing here?
Why does the stream need to be a member?
struct GameBase {
void out(std::ostream& out = std::cout);
// ...
};
In addition to having an std::ofstream as a member, I would use a function that returns an std::ostream&.
For example:
class GameBase {
std::ofstream m_OutputWriter;
protected:
std::ostream& getOutputWriter() {
if (m_OutputWriter)
return m_OutputWriter;
else
return std::cout;
}
...
}
A fully-functioning example:
#include <iostream>
#include <ostream>
std::ostream& get() {
return std::cout;
}
int main() {
get() << "Hello world!\n";
}