Class to output to several ostreams (file and console) - c++

Right, I'm not even sure how to correctly formulate this; I feel it's a bit of an involved question. I'm sure someone can help me out here though.
This is what I want to do:
Have a single class that I can send stuff to, like this.
icl << "Blah blah blah" << std::endl;
I want to be able to .attach() classes that inherit std::basic_ostream to it.
Those classes would then be able to format the output their own way. One might add a timestamp and write to a log, the other might write it to the console, the other might display it in-game.
Anyone care to get me started in the right direction? Here's the idea I pretty much have.
#include <vector>
class OutputMan {
std::vector<std::basic_ostream&> m_Streams;
public:
void attach(std::basic_ostream& os) {
m_Streams.push_back(os);
}
}
Question #1: What do I need to inherit and override to send
icl << "Blah!" << std::endl;
To every stream in m_Streams?
Question #2: How do I inherit std::basic_ostream and create a class that changes the output to, for example, add a timestamp to the start of it? I also want for this class to output to a file.

I think I'd do things a bit differently. I've probably made this just a bit more elaborate than necessary -- I'm afraid I may have gotten a little carried away with trying to put new C++11 features to good use. Anyway, on with the code:
#include <streambuf>
#include <fstream>
#include <vector>
#include <iostream>
#include <initializer_list>
namespace multi {
class buf: public std::streambuf {
std::vector<std::streambuf *> buffers;
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
buf(std::vector<std::ofstream> &buf) {
for (std::ofstream &os : buf)
buffers.push_back(os.rdbuf());
}
void attach(std::streambuf *b) { buffers.push_back(b); }
int_type overflow(int_type c) {
bool eof = false;
for (std::streambuf *buf : buffers)
eof |= (buf -> sputc(c) == traits_type::eof());
return eof ? traits_type::eof() : c;
}
};
class stream : public std::ostream {
std::vector<std::ofstream> streams;
buf outputs;
public:
stream(std::initializer_list<std::string> names)
: streams(names.begin(), names.end()),
outputs(streams),
std::ostream(&outputs)
{ }
void attach(std::ostream &b) {
outputs.attach(b.rdbuf());
}
};
}
int main() {
multi::stream icl({"c:\\out1.txt", "c:\\out2.txt"});
icl.attach(std::cout);
icl << "Blah blah blah" << std::endl;
}
As you can see, this already accepts manipulators (which should work with any manipulator, not just std::endl). If you want to write to multiple files (things that could/can be opened as fstreams) you can specify as many of those names in the constructor as you like (within the limits imposed by your system, of course). For things like std::cout and std::cerr for which you don't necessarily have a file name, you can use attach as you originally intended.
I suppose I should add that I'm not entirely happy with this as-is. It'd take some fairly serious rewriting to do it, but after some thought, I think the "right" way would probably be for multi::stream's ctor to be a variadic template instead, so you'd be able to do something like: multi::stream icl("c:\\out1.txt", std::cout);, and it would sort out how to use each parameter based on its type. I may update this answer to include that capability some time soon.
As far as the second question goes, I've written another answer that covers the basic idea, but is probably a bit overly elaborate, so the part you care about may kind of get lost in the shuffle, so to speak -- it has quite a bit of logic to deal with line lengths that you don't really care about (but does produce each output line with a specified prefix, like you want).

You may need something like this:
class OutputMan {
std::vector<std::ostream*> m_Streams;
public:
void attach(std::ostream *os) {
m_Streams.push_back(os);
}
template <typename T>
OutputMan &operator<<(const T &t) {
for (int i=0; i<m_Streams.size(); i++)
*m_Streams[i] << t;
return *this;
}
};
int main() {
ofstream file("test.txt");
OutputMan x;
x.attach(&cout);
x.attach(&cerr);
x.attach(&file);
x << "Hello" << 123;
}
For simplicity I used std::ostream*. To accept stuffs by << I overloaded operator<<.
Note: If you want OutputMan accepts std::endl as well as other things, read here.

Related

Extending std::cout

I want to extend the usage of std::cout to use my own console/cout wrapper class.
Ideally I would have 2 ostreams, one for regular printing and one that appends a new line.
std::ostream Write;
Write << "Hello, I am " << 99 << " years old.";
prints Hello, I am 99 years old.
std::ostream WriteLine;
WriteLine << "Hello, I am " << 99 << " years old.";
prints Hello, I am 99 years old.\n (an actual new line, not just it escaped)
I would then like to extend this to have error streams (Error and ErrorLine, for example) which prefix "ERROR: " before the message and prints in a different color.
I know I have to create my own streams to add in this functionality, and I followed C++ cout with prefix for prefixing std::cout which was almost what I wanted but not quite. I couldn't figure out how to add a new line to the end of the stream, and the prefix was unreliable, especially when I would do more than a single print statement.
I should also mention I don't want to use overloaded operators to achieve this effect, because I want to be able to daisy-chain things on.
What didn't work
If I did WriteLine >> "First"; then WriteLine << "Second"; I would get weird results like SecondFirst\n or Second\nFirst. My ideal output would be First\nSecond\n. I think it is due to not closing/flushing/resetting the stream properly, but nothing I tried got it to work reliably.
I could get it to work for a single statement, but as soon as I added another print statement, the things I tried to print would switch order, the post/pre fix wouldn't get added in the correct spot, or I would end up with garbage.
I don't care about wchars, because we will always only need a single byte for a single char. Also we will only be working on Windows 10.
This is what I have so far:
Console.h
#include <windows.h>
#include <iostream>
#include <sstream>
#include <string>
class Console {
using Writer = std::ostream;
Console() {}
static const char newline = '\n';
class error_stream: public std::streambuf {
public:
error_stream(std::streambuf* s) : sbuf(s) {}
~error_stream() { overflow('\0'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if(traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch(c) {
case '\n':
case '\r':
{
SetColor(ConsoleColor::Red);
prefix = "ERROR: ";
buffer += c;
if(buffer.size() > 1)
sbuf->sputn(prefix.c_str(), prefix.size());
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
buffer.clear();
SetColor(ConsoleColor::White);
return rc;
}
default:
buffer += c;
return c;
}
}
std::string prefix;
std::streambuf* sbuf;
string buffer;
};
class write_line_stream: public std::streambuf {
public:
write_line_stream(std::streambuf* s) : sbuf(s) {}
~write_line_stream() { overflow('\0'); }
private:
typedef std::basic_string<char_type> string;
int_type overflow(int_type c) {
if(traits_type::eq_int_type(traits_type::eof(), c))
return traits_type::not_eof(c);
switch(c) {
case '\n':
case '\r':
{
buffer += c;
int_type rc = sbuf->sputn(buffer.c_str(), buffer.size());
sbuf->sputn(&newline, 1);
buffer.clear();
return rc;
}
default:
buffer += c;
return c;
}
}
std::streambuf* sbuf;
string buffer;
};
static output_stream outputStream;
static error_stream errorStream;
static write_line_stream writeLineStream;
public:
static void Setup();
static Writer Write;
static Writer WriteLine;
static Writer Err;
};
Console.cpp
#include "Console.h"
Console::Writer Console::Write(nullptr);
Console::Writer Console::WriteLine(nullptr);
Console::Writer Console::Err(nullptr);
Console::error_stream Console::errorStream(std::cout.rdbuf());
Console::write_line_stream Console::writeLineStream(std::cout.rdbuf());
void Console::Setup() {
Write.rdbuf(std::cout.rdbuf());
Err.rdbuf(&errorStream);
WriteLine.rdbuf(&writeLineStream);
}
Main.cpp
int main() {
Console::Setup();
Console::Write << "First" << "Second";
Console::WriteLine << "Third";
Console::WriteLine << "Fourth";
Console::Write << "Fifth";
Console::Error << "Sixth";
Console::ErrorLine << "Seventh";
Console::WriteLine << "Eighth";
}
Which should give an output of
FirstSecondThird
Fourth
FifthERROR: SixthERROR: Seventh
Eighth
Press any key to continue...
Any help and/or suggestions are appreciated.
There are multiple concerns here which do require different approaches. Some of the description also seems that the actual desire isn't quite clear. The most problematic requirement is that a newline needs to be inserted apparently at the end of a statement. That's certainly doable but effectively does require a temporary being around.
Before going there I want to point out that most other languages offering a print-line(....) construct delineate what is going onto a line using a function call. There is no doubt where the newline goes. If C++ I/O would be created now I'd be quite certain that it would be based on a variadic (not vararg) function template. This way print something at the end of the expression is trivial. Using a suitable manipulator at the end of the line (although probably not std::endl but maybe a custom nl) would be an easy approach.
The basics of adding a newline at the end of expression would be using a destructor of a suitable temporary object to add it. The straight forward way would be something like this:
#include <iostream>
class newline_writer
: public std::ostream {
bool need_newline = true;
public:
newline_writer(std::streambuf* sbuf)
: std::ios(sbuf), std::ostream(sbuf) {
}
newline_writer(newline_writer&& other)
: newline_writer(other.rdbuf()) {
other.need_newline = false;
}
~newline_writer() { this->need_newline && *this << '\n'; }
};
newline_writer writeline() {
return newline_writer(std::cout.rdbuf());
}
int main() {
writeline() << "hello, " << "world";
}
This works reasonable nice. The notation in the question doesn't use a function call, though. So, instead of writing
writeline() << "hello";
it seems necessary to write
writeline << "hello";
instead and still add a newline. This complicates matters a bit: essentially, writeline now needs to be an object which somehow causes another object to jump into existence upon use so the latter can do its work in the destructor. Using a conversion won't work. However, overloading an output operator to return a suitable object does work, e.g.:
class writeliner {
std::streambuf* sbuf;
public:
writeliner(std::streambuf* sbuf): sbuf(sbuf) {}
template <typename T>
newline_writer operator<< (T&& value) {
newline_writer rc(sbuf);
rc << std::forward<T>(value);
return rc;
}
newline_writer operator<< (std::ostream& (*manip)(std::ostream&)) {
newline_writer rc(sbuf);
rc << manip;
return rc;
}
} writeline(std::cout.rdbuf());
int main() {
writeline << "hello" << "world";
writeline << std::endl;
}
The primary purpose of the overloaded shift operators is to create a suitable temporary object. They don't try to mess with the content of the character stream. Personally, I'd rather have the extra parenthesis than using this somewhat messy approach but it does work. What is kind of important is that the operator is also overloaded for manipulators, e.g., to allow the second statement with std::endl. Without the overload the type of endl can't be deduce.
The next bit is writing the prefix and mixing multiple streams. The important bit here is to realize that you'd want to one of two things:
Immediately write the characters to a common buffer. The buffer is most like just another stream buffer, e.g., the destination std::streambuf.
If the character should be buffered locally in separate stream buffers, the corresponding streams need be flushed in a timely manner, e.g., after each insertion (by setting the std::ios_base::unitbuf bit) or, latest, at the end of the expression, e.g., using an auxiliary class similar to the newline_writer.
Passing through the characters immediately is fairly straight forward. The only slight complication is to know when to write a prefix: upon the first non-newline, non-carriage-return return after a newline or a carriage return (other definitions are possibly and should be easily adaptable). The important aspect is that stream buffer doesn't really buffer but actually passes through the character to the underlying [shared] stream buffer:
class prefixbuf
: public std::streambuf {
std::string prefix;
bool need_prefix = true;
std::streambuf* sbuf;
int overflow(int c) {
if (c == std::char_traits<char>::eof()) {
return std::char_traits<char>::not_eof(c);
}
switch (c) {
case '\n':
case '\r':
need_prefix = true;
break;
default:
if (need_prefix) {
this->sbuf->sputn(this->prefix.c_str(), this->prefix.size());
need_prefix = false;
}
}
return this->sbuf->sputc(c);
}
int sync() {
return this->sbuf->pubsync();
}
public:
prefixbuf(std::string prefix, std::streambuf* sbuf)
: prefix(std::move(prefix)), sbuf(sbuf) {
}
};
The remaining business is to set up the relevant objects in the Console namespace. However, doing so is rather straight forward:
namespace Console {
prefixbuf errorPrefix("ERROR", std::cout.rdbuf());
std::ostream Write(std::cout.rdbuf());
writeliner WriteLine(std::cout.rdbuf());
std::ostream Error(&errorPrefix);
writeliner ErrorLine(&errorPrefix);
}
I except that the approach adding the newline creates a custom type I think that matches the original goes. I don't think the temporary object can be avoided to automatically create a newline at the end of a statement.
All that said, I think you should use C++ idioms and not try to replicate some other language in C++. The way to choose whether a line end in newline or not in C++ is to write, well, a newline where one should appear potentially by way of a suitable manipulator.

Place setw() as a variable

I have this sample block of code:
#include <iostream>
#include <iomanip>
#include <string>
using namespace std;
int main(){
string blank = " ";
cout << "Hello" << blank << "47";
}
I have a lot of cout's of this type in my original code.
I want to be able to change the blank string to setw(2) function without having to replace blank with setw(2) on each and every cout I have in my code.
So is there a way to set a cpp function to a variable?
So I can call the function by typing the name?
for example:
func blank = setw(2);
cout<< "Hello" << blank << "47";
The type of std::setw(x) is unspecified, but you don't need to know it.
You can just use auto:
auto blank = std::setw(2);
As #StoryTeller noted, while this should work on sane implementations, it's not guaranteed to.
A safer option would be to make a class with overloaded <<:
struct blank_t {} blank;
std::ostream &operator<<(std::ostream &s, blank_t)
{
return s << std::setw(2);
}
std::setw is a manipulator. Its type is unspecified and implementation specific.
So is there a way to set a cpp function to a variable?
With C++11 you can use function objects, notably std::function. And you also have lambda expressions.
I am not sure you want to use it in your case.
So learn to use your source code editor. Replace every occurrence of blank with the appropriate stuff, that is std::setw(2) .... That makes your code more readable. Good editors are able to do that easily.
You could abuse the preprocessor, and have
#define blank setw(2)
but in your case that is a bad idea (because the code remains unreadable). Even using auto as answered by HolyBlackCat keeps your code unreadable and confusing.
Code is much more often read than written. Keep it readable (even by yourself, in a few weeks).
If you have a huge (million-line) project, spend perhaps a few minutes to write some script to change your source code in such case. BTW, with GNU emacs it is easy (since emacs is a scriptable editor).
An alternative solution is to write a small wrapper class whose only purpose is to provide an overloaded operator<< for an encapsulated referenced object. You can templatise that class so it works with everything that you could feed to an std::ostream in the first place.
Here is an example:
#include <iostream>
#include <iomanip>
#include <string>
template <class T>
struct Blank {
Blank(T const& t) : t(t) {}
T const& t;
};
// utility function so that you can use type deduction at the call site:
template <class T>
Blank<T> blank(T const& t) {
return Blank<T>(t);
}
template <class T>
std::ostream& operator<<(std::ostream& os, Blank<T> const& blank) {
os << std::setw(2) << blank.t;
return os;
}
int main() {
std::cout << "Hello" << blank("4") << blank(7) << blank(std::string("8")) << '\n';
}
It's not exactly the syntax you've asked for, but it comes pretty close.
You also have to make sure that no encapsulated object is destroyed before it's used in operator<< (because then you'd have undefined behaviour due to a dangling reference), but that's easy to accomplish if never create named Blank objects.

Best way to send multiple arguments of different types to a method for processing. c++

Currently I have a method that works as follows:
std::stringstream ss; ss << "lives:" << this->Lives;
Text->RenderText(ss.str(), font, x, y, scale,color);
Now this seems messy to me and I wanted to reduce it down to one line.
But I cant seem to think of a way to do it cleanly.
I thought of using varidic functions, but that restricts me to one type and I have to specify the number of arguments.
Also though of using a std::initializer_list or varidic templates but it doesn't seem any nicer.
In this solution: Here An answer provided by Georg Fritzsche showed a posible solution using:
helper() << a << b << c;
But the actual implementation of it I'm.... not sure of.
Something akin to:
Text->render(font, x, y, scale,color) << "lives:" << this->Lives;
would be nice, but in the method I'm not sure how to define it.
I cant return a stringstream object, because I cant access it after the return.
So how does a method like this with chaining << work?
Return a temporary object that accumulates all the parts of your string, then when it is automatically destroyed at the end of the statement, have it render the content in its destructor.
#include <utility>
#include <string>
#include <sstream>
#include <iostream>
using namespace std;
class Renderer {
stringstream sstream;
float x;
float y;
public:
Renderer(float x, float y) : x(x), y(y){}
template<class T>
Renderer && operator<<(T&& t) {
sstream << std::forward<T>(t);
return std::move(*this);
};
~Renderer() {
// your real code replaces the line below..
cout << sstream.str() << endl;
}
};
Renderer render(float x, float y) {
return Renderer(x, y);
}
int main() {
int i = 5;
render() << "foo" << i;
}
live: https://wandbox.org/permlink/UToweQELJ4jt0QYl
How I'd deal with this
Okay, so you have this:
std::stringstream ss; ss << "lives:" << this->Lives;
Text->RenderText(ss.str(), font, x, y, scale,color);
Now if you really want to do it in a single line, why not put the string generation into a single function call, something specific like
std::string life_text(int lifecount){
std::stringstream ss;
ss<<"lives:"<<lifecount;
return ss.str();
}
So you can call render like this:
Text->render(life_text(lives), x, y, scale,color);
What you're looking for
First, before I answer the question that you asked, the << operator does not imply method chaining. At least not in vanilla C++, in fact, I don't think it's used anywhere like that in c++.
The stream objects aren't really chaining a method, but calling something like
template<typename T> std::stringstream& operator<<(std::stringstream& rightside,T leftside){
rightside.append(leftside);
return rightside;
}
So what happens at each step of that is something like:
stringstream r;
r<<"lives:";
r<<this->lives;
What you are asking for isn't really all that simple. You would need to change the rendertext function to return a new sort of object that you can pass arguments to. That's hard.
Second of all, that would mean that your evaluation order would make this somewhat more challenging. There are ways around that, but I don't know if this is a situation where a simple convenience function like above wouldn't be better.
If you're dead set on doing this that way, then you might have to do something that is really potentially very problematic. You'd have to make the object call the actual render function(which I assume you probably have from some framework) at its disposal.
Fine, but now you've required adding some scope that might matter if you need this done in a specific order. It would look, potentially, like this:
{
Text->render(x,y,scale,color)<<"lives:"<<this->Lives;
}
To my eyes, that looks frustrating.
I'll answer any questions you might have relating to my answer, if you'd like, but, at least to my eyes, your original goal seems like you're barking up the wrong tree with how you'd like to do this.
Something approaching a solution in the manner you wanted
template<std::function<typename ReturnType(std::string&,typename Ts...)> Func>
class caller{
std::stringstream r;
Ts... arguments;
Func storedFunction;
public:
caller(Func x,typename Ts...):storedFunction(x){
arguments=Ts;
}
~caller(){
Func(r.str(),...Ts);
}
friend template<typename S,typename P> caller<S>& operator<<(caller<S>&,T value);
};
template<typename S,typename P> caller<S>& operator<<(caller<S>& c, T value){
c.r<<value;
}
caller a_suitable_name(std::bind(&Text::Render,&Text),_those_other_arguments);
caller<<"lives:"<
This isn't likely to work in its present form, but I don't have time to finish the definition.

Redirect debug output to null stream instead of std::cerr

A software library that I am working with writes a lot of debug output to std::cerr, but redirects that output to a null stream if I tell it to be quiet. This is a simplified main.cpp that shows how the code tries to achieve this:
#include <iostream>
#include <fstream>
#include <cassert>
// The stream that debug output is sent to. By default
// this points to std::cerr.
std::ostream* debugStream(&std::cerr);
// Throughout the library's codebase this function is called
// to get the stream that debug output should be sent to.
std::ostream& DebugStream()
{
return *debugStream;
}
// Null stream. This file stream will never be opened and acts
// as a null stream for DebugStream().
std::ofstream nullStream;
// Redirects debug output to the null stream
void BeQuiet()
{
debugStream = &nullStream;
}
int main(int argc, char** argv)
{
DebugStream() << "foo" << std::endl;
BeQuiet();
DebugStream() << "bar" << std::endl;
assert(debugStream->good());
return 0;
}
When you run this program, you will notice that the string "bar" is correctly sent to the null stream. However, I noticed that the assertion fails. Is this something that I should be concerned about? Or is this just a slightly ugly detail of the approach chosen by the library developers?
If you feel like it, suggestions for better alternatives are welcome. Some constraints:
The library is cross-platform, so I think using opening /dev/null is not a valid solution as it would not work on Windows
The library uses standard C++, so any alternative solutions should not use compiler-specific stuff
There is no real need to be worried about the stream not being good()! Since the output operators don't really do anything wirh a stream in failure mode the different entities being logged are not formatted, i.e., the code does run faster compared to alternative approaches.
Note that you don't really need a second stream to disable output:
Assuming all output operators are well-behaved, you can just set std::ios_base::failbit:
debugStream().setstate(std::ios_base::failbit);
If there are misbehaved output which write to a stream even if it isn't good() you can just set its stream buffer to null:
debugStream().rdbuf(nullptr);
If you really want your stream to remain in good() state, you'd install a stream buffer which just consumes characters. Note, however, that you want to give this stream buffer a buffer as having overflow() called for each char is fairly exensive:
struct nullbuf
: std::streambuf {
char buf[256];
int overflow(int c) {
this->setp(this->buf, this->buf + 256);
return std::char_traits<char>::not_eof(c);
}
};
...
nullbuf sbuf;
debugStream().rdbuf(&sbuf);
...
debugStream().rdbuf(0);
It is necessary to reset the stream's stream buffer because the destructor of an std::ostream will flush the stresm buffer (i.e., it calls pubsync()). Doing so on a destroyed stream buffer won't work.
Personally, I would go with setting std::ios_base::failbit.
In this answer you find a general helper to redirect any stream to any other stream:
class stream_redirector {
public:
stream_redirector(std::ios& stream, std::streambuf* newBuf) :
savedBuf_(stream.rdbuf()), stream_(stream)
{
stream_.rdbuf(newBuf);
}
~stream_redirector() {
stream_.rdbuf(savedBuf_);
}
private:
std::streambuf* savedBuf_;
std::ios& stream_;
};
and now all you need is a no-op stream from this answer which discards anything:
template <class cT, class traits = std::char_traits<cT> >
class basic_nullbuf: public std::basic_streambuf<cT, traits> {
typename traits::int_type overflow(typename traits::int_type c)
{
return traits::not_eof(c); // indicate success
}
};
template <class cT, class traits = std::char_traits<cT> >
class basic_onullstream: public std::basic_ostream<cT, traits> {
public:
basic_onullstream():
std::basic_ios<cT, traits>(&m_sbuf),
std::basic_ostream<cT, traits>(&m_sbuf)
{
// note: the original code is missing the required this->
this->init(&m_sbuf);
}
private:
basic_nullbuf<cT, traits> m_sbuf;
};
typedef basic_onullstream<char> onullstream;
typedef basic_onullstream<wchar_t> wonullstream;
and you're good to go:
int main(int argc, char** argv)
{
std::cerr << "foo" << std::endl;
{
onullstream nos;
stream_redirector sr( std::cerr, nos.rdbuf() );
std::cerr << "bar" << std::endl;
}
std::cerr << "baz" << std::endl;
}
and finally here's a live example in case you want to play with it. This method has the additional benefit that you (and your colleagues) can still use std::cerr in your code and you can turn it off and on again at will :)

Ways to write a vector of a class to a file

I'm not sure how I should word this, so I'll attempt to put it in code. (This has many errors I know it will not compile it is simply to show what I want to do because I can't put it in words)
using namespace std; //for correctness sake
class foo {
public:
foo(int a=0, int n=0);
void stuff(int a);
void function(int n);
const int get_function() {return n;}
const int get_stuff(){return a;}
private:
int n, a;
};
struct Store{
public: get_foo(){return vector<f.foo>;} //I'm not too sure of the syntax here but you get the idea
private:
foo f;
}
Basically I want to take all the information that is returned in class foo, and output this, formatted, to a file. Thing is, I need to make many of these within the file and it has to be able to read it back for it to be worth anything.
So just appending each consecutive foo class to the file won't work(at least I don't see how).
I tried using ostream to overload the << operator, but I'm not sure how to call it to write it to the file. Any suggestions are welcome! Thanks.
I think your Store should be like this:
struct Store
{
public:
std::vector<foo> get_foo()
{
return f;
}
private:
std::vector<foo> f;
};
To overload << of std::ostream:
std::ostream& operator<<(std::ostream& out, const Store& f)
{
for (auto &x : f.get_foo())
out << x.get_function() << ", " << x.get_stuff() << "\n";
return out;
}
//Without auto
std::ostream& operator<<(std::ostream& out, const Store& f)
{
std::vector<foo> q = f;
for (int i=0; i<q.size(); i++)
out << q[i].get_function() << ", " << q[i].get_stuff() << "\n";
return out;
}
There are many tings wrong with your code.
So many that it's clear that you never read any C++ book and are just experimenting with a compiler.
Don't do that. C++ is really the worst language in the world to approach that way for many independent reasons.
No matter how smart you are.
Actually being smart is sort of a problem in certain areas because many C++ rules are not the result of a coherent logical design, but of historical evolution and committee decisions. Not even Hari Seldon would be able to foresee correctly what a committee would decide, you cannot deduce history.
Just pick a good book and read it cover to cover. There is no other sensible way to learn C++.
About writing structs to a file the topic is normally called "serialization" and takes care of the slightly more general problem of converting live objects into a dead sequence of bytes (written to a file or sent over the network) and the inverse problem "deserialization" of converting the sequence of bytes back into live objects (on the same system, on another identical system or even on a different system).
There are many facets of this problem, for example if your concern is about portability between systems, speed, size of the byte sequence, ability to reload bytes sequences that were saved back when your classes were slightly different because you evolved the program (versioning).
The simplest thing you can do is just fwrite things to a file, but this is most often simply nonsense in C++ and is a terrible way for many reasons even when it's technically possible. For example you cannot directly fwrite an std::vector object and hope to read it back.
I think you need something like this:
template<typename T>
std::ostream& operator << (std::ostream& out, const std::vector<T*>& elements)
{
for (size_t i = 0; i < elements.size(); i++)
out << elements[i] << ", ";
return out << std::endl;
}