For an API that I am working on, I want to allow the user to insert custom objects into an ostream, but these objects have no meaning on their own, and are too memory constrained to include an additional pointer or reference for context. (Think tens of millions of 16-/32-/48-bit objects in an embedded system with limited memory.)
Suppose the user initializes the underlying context, and looks up one of these objects:
DDB ddb("xc5vlx330t");
Tilewire tw = ddb.lookUpTilewire("DSP_X34Y0", "DSP_IMUX_B5_3");
...
std::cout << complexDataStructure;
In an entirely different scope, possibly nested far away from the user's explicit code, we may need to insert the object into an ostream, with ddb unavailable.
os << tw;
The actual value encapsulated by tw is 97,594,974, but the desired output is this:
DSP_IMUX_B5_3#[263,84] DSP "DSP_X34Y0" (1488#77406)
In order for this to work, the appropriate insertion operator would need access to ddb, but it cannot rely on static or global variables or functions (for multithreading reasons). What I'd like to do is allow the user to request and use a stream wrapper kind of like this:
ostream& wrappedCout = ddb.getWrappedOstream(std::cout);
The returned subclass of ostream would include a reference to ddb for use by special stream inserters that needed it, and a reference to the original stream—std::cout in this case—where it would forward all of its output.
Unfortunately, the inheritance or composition schemes that I have come up with are messy to code up (not an enormous concern), and possibly problematic for the user (a much larger concern). Any suggestions on how to elegantly make ddb available to insertion operators? I am marginally aware of boost.Iostreams, but not sure that it will help me out here.
Write a custom stream manipulator that stores a reference to ddb using the iword/pword mechanism. Here is an example, you'd need to add locking around the iwork_indexes map in a multithreaded program.
class dbb
{
public:
explicit dbb(int value) : m_value(value) {}
int value() const { return m_value; }
private:
int m_value;
};
class dbb_reliant_type
{
public:
dbb_reliant_type(const std::string& value) : m_value(value) {}
const std::string& value() const { return m_value; }
private:
std::string m_value;
};
typedef std::map<std::ostream*, int> iword_map;
iword_map iword_indexes;
inline int get_iword_index(std::ostream& os)
{
iword_map::const_iterator index = iword_indexes.find(&os);
if(index == iword_indexes.end())
{
std::pair<iword_map::iterator, bool> inserted = iword_indexes.insert(std::make_pair(&os, os.xalloc()));
index = inserted.first;
}
return index->second;
}
inline std::ostream& operator<<(std::ostream& os, const dbb& value)
{
const int index = get_iword_index(os);
if(os.pword(index) == 0)
os.pword(index) = &const_cast<dbb&>(value);
return os;
}
std::ostream& operator<<(std::ostream& os, const dbb_reliant_type& value)
{
const int index = get_iword_index(os);
dbb* deebeebee = reinterpret_cast<dbb*>(os.pword(index));
os << value.value() << "(" << deebeebee->value() << ")";
return os;
}
int main(int, char**)
{
dbb deebeebee(5);
dbb_reliant_type variable("blah");
std::cout << deebeebee << variable << std::endl;
return 0;
}
I'm not entirely sure if I understand what can be accessed at what time and what can and can't change, but....can you do something like this
struct TilewireFormatter {
DDB *ddb;
TilewireFormatter(DDB* d) : ddb(d) {}
print(std::ostream& out, const Tilewire& obj) {
// some formatting dependent on ddb
out << obj;
}
};
and replace out << tw; with formatter.print(out, tw);
then not provide any sort of << operator overload for Tilewire and pass an instance of TilewireFormatter around that's used to format them based on what ddb is?
I'm new at this, so in case providing my own answer gets in the way of me sharing the credit with Gary, well, Gary pointed out what I had just stumbled upon moments before through the same reference: Stream Storage for Private Use: iword, pword, and xalloc
#include <iostream>
// statically request a storage spot that can be associated with any stream
const int iosDdbIndex = std::ios_base::xalloc();
class DDB {
public:
// give the stream a pointer to ourselves
void bless(std::ostream& os) { os.pword(iosDdbIndex) = this; }
// provide a function that the insertion operator can access
int getSomething(void) { return 50; }
};
class Tilewire {
friend std::ostream& operator<< (std::ostream& os, Tilewire tilewire);
// encapsulate a dummy value
int m;
public:
// construct the Tilewire
Tilewire(int m) : m(m) {}
};
std::ostream& operator<< (std::ostream& os, Tilewire tilewire) {
// look up the pointer to the DDB object
DDB* ddbPtr = (DDB*) os.pword(iosDdbIndex);
// insert normally, and prove that we can access the DDB object's methods
return os << "Tilewire(" << tilewire.m << ") with DDB param " << ddbPtr->getSomething();
}
int main (int argc, char * const argv[]) {
DDB ddb;
ddb.bless(std::cout);
std::cout << Tilewire(0) << std::endl;
return 0;
}
Rather than fudging around and trying to find a way to pass contextual information while using the insertion operator, I suggest you make something like a print method like choobablue suggests. It's a nice and simple solution and anything fancier is probably more trouble than it's worth.
I also find it odd that you choose iostreams for an embedded system. They're one of the most bloated parts of the C++ standard library (not just by implementation, but by design) and if you are working on an embedded system, you could just as well roll your own alternative of this (still based on the basic design of iostreams) and can probably do it just as quickly as trying to use iostream effectively and across multiple threads.
Related
I'm learning C++, and have a question related to classes and templates.
I know it's good practice to have "getters" for every variable in your class and a "setter" function. But with the code shown below, should you have a "getter" function for the array? In theory, the print function would serve the same purpose as the "getter" function would - print out everything in the array. If it is required, what would the correct code be to return that array? The array is an array of class objects.
My thinking and the code thus far:
queue.h
#pragma once
template<class T>
class Queue {
public:
Queue(int = 1);
~Queue();
void setQueue(int);
void enqueue(T);
void dequeue();
const T* getQueueArray() const;
const int getArraySize() const;
const int getArrayIndex() const;
void printQueue();
private:
T* queueArray;
int arraySize, arrayIndex;
};
queue.cpp
#include <iostream>
#include "queue.h"
template<class T>
Queue<T>::Queue(int arraySize) {
this->setQueue(arraySize);
}
template<class T>
Queue<T>::~Queue() {
delete [] this->queueArray;
}
template<class T>
void Queue<T>::setQueue(int arraySize) {
this->arraySize = arraySize;
delete [] this->queueArray;
this->queueArray = new T[arraySize];
this->arrayIndex = 0;
}
template<class T>
void Queue<T>::enqueue(T object) {
if (this->arrayIndex == this->arraySize) {
std::cout << "Rinda ir pilna, nevar pievienot elementu!\n";
}
else {
this->queueArray[this->arrayIndex] = object;
this->arrayIndex++;
}
}
template<class T>
void Queue<T>::dequeue() {
if (this->arrayIndex == 0) {
std::cout << "Rinda ir tuksa!\n";
}
else {
for (int i = 0; i < this->arraySize - 1; i++) {
this->queueArray[i] = this->queueArray[i + 1];
}
this->arrayIndex--;
}
}
template<class T>
const T* Queue<T>::getQueueArray() const {
return this->queueArray;
}
template<class T>
const int Queue<T>::getArraySize() const {
return this->arraySize;
}
template<class T>
const int Queue<T>::getArrayIndex() const {
return this->arrayIndex;
}
template<class T>
void Queue<T>::printQueue() {
for (int i = 0; i < this->arrayIndex; i++) {
std::cout << i + 1 << ". ";
this->queueArray[i].printHuman();
}
}
The array getter function works and returns a memory address. Is that behavior correct?
And I'd like to ask another question, for class print functions, which would be the better of the 2:
std::cout << "something something" << classVariable;
or
std::cout << "something something" << getClassVariable();
One way is accessing the variables directly and the other is using the "getter" functions. Does it matter and does using functions like that impact performance in a noticable way?
This post is largely opinion-based, but I'm going to offer my perspective. You've received comments telling you a few things.
First, I'd encourage you to do things "the C++ way". Templates are done in the header, and it's really gross to "#include "queue.cpp". But I understand at least for an example that's maybe okay, as it lets you focus on other things than all the code to implement the entire template. Just don't do it in practice.
As for getters and setters -- I disagree with some of the comments you're getting. I absolutely would NOT put a setter on the internal structure, but if this is a serious class, I'd absolutely implement some way to inspect the full contents.
Imagine, after all, that someone wants to be able to count how many elements in the queue have fulfill a particular constraint. You don't want to try to anticipate evreything someone might want to do. But you can certainly put some means of inspecting the contents, either by being able to get the current queue (const) or via iterators. Iterators are harder to implement, but they fit a lot of other algorithms. See the entire contents of #include .
So:
Yes on some sort of access system (a getter / iterator)
No on a setter
In addition to this, I'm not sure why your sample code isn't willing to grow the list if necessary, but if it's not going to, it should somehow indicate to the caller that it failed to enqueue properly.
First of all for templated classes, having the declaration in a header file and having the definitions on a source file wont work. So try putting them in the same header file.
I know it's good practice to have "getters" for every variable in your class and a "setter" function
Yes that is true but not always. Getting the actual data pointer will help for example when copying data to a buffer. Setting is usually done by assignment operators,
Value& operator=(const Object& other) { ... } // Copy assign operator.
Value& operator=(Object&& other) { ... } // Move assign operator.
So I would advice not to have a setter in these type of objects.
And I'd like to ask another question, for class print functions, which would be the better of the 2:
std::cout << "something something" << classVariable; or std::cout << "something something" << getClassVariable();
This is opinion based and usually you print the content to the console by overloading the << operator,
template<class T>
ostream& operator<<(ostream& os, const Queue<T>& dt)
{
os << /* print content */;
return os;
}
int main()
{
Queue<int> queue;
std::cout << "Printing queue! " << queue;
}
One way is accessing the variables directly and the other is using the "getter" functions. Does it matter and does using functions like that impact performance in a noticable way
Nope they wont. If you inline the functions, there wont be no performance differences. And make sure you enable optimizations or else additional debug information would slow it down. I would argue that using a getter function would be safer.
tl;dr: Is there a way to add a default argument from the current scope to all implicit constructors in C++?
I am currently designing an interface for an embedded language in C++. The goal is to make the creation of syntactically correct expressions both typesafe and convenient. Right now, I think that learning a heavyweight implementation like boost::proto will itnroduce a too large latency into the development, so I attempt to roll my own implementation.
Here is a small demo:
#include <iostream>
#include <string>
#include <sstream>
class ExprBuilder
{
public:
ExprBuilder(const int val) : val(std::to_string(val)) {}
ExprBuilder(const std::string val) : val(val) {}
ExprBuilder(const char* val) : val(val) {}
ExprBuilder(const ExprBuilder& lhs, const ExprBuilder& arg) {
std::stringstream ss;
ss << "(" << lhs.val << " " << arg.val << ")";
val = ss.str();
}
const ExprBuilder operator()(const ExprBuilder& l) const {
return ExprBuilder(*this, l);
}
template<typename... Args>
const ExprBuilder operator()(const ExprBuilder& arg, Args... args) const
{
return (*this)(arg)(args...) ;
}
std::string val;
};
std::ostream& operator<<(std::ostream& os, const ExprBuilder& e)
{
os << e.val;
return os;
}
int main() {
ExprBuilder f("f");
std::cout << f(23, "foo", "baz") << std::endl;
}
As you can see, it is fairly simple to embedd expressions due to C++ overloading and implicit conversions.
I am facing a practical problem however: In the example above, all data was allocated in the form of std::string objects. In practice, I need something more complex (AST nodes) that are allocated on the heap and managed by a dedicated owner (legacy code, cannot be changed). So I have to pass a unique argument (said owner) and use it for the allocations. I'd rather not use a static field here.
What I am searching is a way to use ask the user to provide such an owner everytime the builder is used, but in a convenient way. Something like a dynamically scoped variable would be great. Is there a way to obtain the following in C++:
class ExprBuilder
{
...
ExprBuilder(const ExprBuilder& lhs, const ExprBuilder& arg) {
return ExprBuilder(owner.allocate(lhs, rhs)); // use the owner implicitly
}
...
};
int main() {
Owner owner; // used in all ExprBuilder instances in the current scope
ExprBuilder f("f");
std::cout << f(23, "foo", "baz") << std::endl;
}
Is this possible?
edit: I'd like to clarify why I do (up until now) not consider a global variable. The owner has to be manually released by the user of the builder at some point, hence I cannot create one ad hoc. Hence, the user might "forget" the owner altogether. To avoid this, I am searching a way to enforce the presence of the owner by the typechecker.
This is hardly possible without global / static variables, because without global / static information, the local variables Owner owner and ExprBuilder f cannot know anything about each other.
I think the cleanest way is to add a
static Owner* current_owner;
to the ExprBuilder class. Then you can add a new class ScopedCurrentOwnerLock, which sets the current_owner in the constructor and sets it to nullptr in the destructor. Then you can use it similar to a mutex lock:
class ScopedCurrentOwnerLock {
public:
ScopedCurrentOwnerLock(Owner const& owner) {
ExprBuilder::current_owner = &owner;
}
~ScopedCurrentOwnerLock() {
ExprBuilder::current_owner = nullptr;
}
};
int main() {
Owner owner;
ScopedCurrentOwnerLock lock(owner);
ExprBuilder f("f");
}
If you have access to the Owner code, you can omit the ScopedCurrentOwnerLock class and directly set / unset the pointer in the constructor/destructor of Owner.
Please be aware of the following two problems with this solution:
If the owner goes out of scope before the lock goes out of scope, you have an invalid pointer.
The static pointer has unpredictable behaviour if you have multiple locks at the same time, e. g. due to multithreading.
All your ExprBuilders have a dependancy on Owner, and you rightly don't want global state. So you have to pass owner to every constructor.
If you really don't want to add owner, to all your instantiations in a block, you can create a factory to pass it for you.
struct ExprBuilderFactory
{
Owner & owner;
ExprBuilder operator()(int val) { return ExprBuilder(owner, val); }
ExprBuilder operator()(char * val) { return ExprBuilder(owner, val); }
// etc
}
int main() {
Owner owner;
ExprBuilderFactory factory{ owner };
ExprBuilder f = factory("f");
}
I'm trying to create some I/O manipulators to allow a user to modify the output format of a custom type.
Say I have a Foo object: I might want to either output it in a nice, human-readable format (pretty printing), or I might want to print it in a condensed form to save space when serialized.
So, it would be nice to have custom I/O manipulators like condensed and pretty that would modify the internal flags of a facet, so I could say something like:
Foo f;
...
std::cout << pretty << f; // output human-readable format
std::cout << condensed << f; // output condensed format
The problem I always run into is the fact that once a facet object is created, it can only be retrieved later by using std::use_facet, which returns a const reference. This means I can't later modify any of the internal facet flags.
Consider a simple facet:
class my_facet : public std::locale::facet
{
public:
my_facet() : m_pretty(false), m_condensed(false)
{ }
void set_pretty(bool b) { m_pretty = b; }
void set_condensed(bool b) { m_condensed = b; }
static std::locale::id id;
private:
bool m_pretty;
bool m_condensed;
};
I could then create I/O manipulators like:
template <class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& pretty(std::basic_ostream<CharT, Traits>& os)
{
my_facet<CharT>* facet = new my_facet();
facet->set_pretty(true);
facet->set_condensed(false);
std::locale loc = std::locale(os.getloc(), facet);
os.imbue(loc);
return os;
}
That works nicely... but what if I want to allow the user to specify additional flags or formatting options, like say, an indentation option that allows the user to specify a number of spaces to indent, like this:
std::cout << pretty << indent(4) << f;
The problem is that each I/O manipulator has to recreate the facet object, and so previous flags set are lost. The reason is that there's no way to access a non-const reference to the existing facet.
I want to say:
template <class CharT, class Traits>
inline std::basic_ostream<CharT, Traits>& operator << (std::basic_ostream<CharT, Traits>& os,
const indent& ind)
{
const my_facet<CharT>& facet = std::use_facet<my_facet>(os.getloc());
facet.set_indentation(ind.value()); // Error: facet is const!
return os;
}
...but of course, that won't work, because facet is const. The only way I can see around this is making all internal flags mutable, which is absurd.
So, I'm sensing that I'm just doing this wrong. There doesn't seem to be any way to get a non-const reference to an existing facet, so I think I'm going about this whole thing the wrong way.
So, how is this sort of thing usually achieved? How can I write I/O manipulators that can be chained together to set different flags, like:
std::cout << pretty << indent(3) << etc ...
The accepted way of storing custom formatting state is with memory allocated by std::ios_base::xalloc. For example (abridged, live demo with full code here):
class MyFancyManipulator
{
static int myidx;
int st;
public:
MyFancyManipulator(int st) : st(st) {};
template <typename Ch, typename Tr> friend
std::basic_ostream<Ch, Tr>& operator<< (std::basic_ostream<Ch, Tr>& str,
const MyFancyManipulator& man) {
//
// Transfer state from the manipulator to the stream
//
str.iword(MyFancyManipulator::myidx) = man.st;
return str;
}
};
// Allocate index for the state variable
// This is thread safe per C++14 standard
int MyFancyManipulator::myidx = std::ios_base::xalloc();
// ... In some custom operator<<
int state = str.iword(MyFancyManipulator::myidx);
I'm trying to make a simple logger class, and I want the ability to either log to either a generic ostream (cout/cerr) or a file. The design I have in mind is to allow the constructor to either take an ostream& or a filename, and in the latter case create an ofstream& and assign that to the class' private ostream& like so:
class Log {
private:
std::ostream& os;
public:
Log(std::ostream& os = std::cout): os(os) { }
Log(std::string filename) {
std::ofstream ofs(filename);
if (!ofs.is_open())
// do errorry things
os = ofs;
}
};
Doing such gives me an error that ofstream's assignment operator is private. Looking over that again, it occurred to me that making a reference to a local object probably wouldn't work, and making os a pointer to an ostream and declaring and deleting it on the heap worked with the ofstream case, though not with the ostream case, where the ostream already exists and is just being referenced by os (because the only place to delete os would be in the constructor, and I don't know of a way to determine whether or not os is pointing to an ofstream created on the heap or not).
So how can I make this work, i.e. make os reference an ofstream initialized with a filename in the constructor?
For one thing, you can't rebind references once they're created, you can only initialise them. You might think you could do this:
Log(std::string filename) : os(std::ofstream(filename)) {
if (!os.is_open())
// do errorry things
}
But that's no good because you are making os refer to a temporary variable.
When you need a reference that has to be optional, that is, it needs to refer to something sometimes and not other times, what you really need is a pointer:
class Log {
private:
std::ostream* os;
bool dynamic;
public:
Log(std::ostream& os = std::cout): os(&os), dynamic(false) { }
Log(std::string filename) : dynamic(true) {
std::ofstream* ofs = new std::ofstream(filename);
if (!ofs->is_open())
// do errorry things and deallocate ofs if necessary
os = ofs;
}
~Log() { if (dynamic) delete os; }
};
The above example is just to show you what is going on, but you probably will want to manage it with a smart pointer. As Ben Voigt points out, there are a lot of gotchas that will cause unforeseen and undesired behaviour in your program; for example, when you try to make a copy of the above class, it will hit the fan. Here is an example of the above using smart pointers:
class Log {
private:
std::unique_ptr<std::ostream, std::function<void(std::ostream*)>> os;
public:
Log(std::ostream& os = std::cout): os(&os, [](ostream*){}) { }
Log(std::string filename) : os(new std::ofstream(filename), std::default_delete<std::ostream>()) {
if (!dynamic_cast<std::ofstream&>(*os).is_open())
// do errorry things and don't have to deallocate os
}
};
The unusual os(&os, [](ostream*){}) makes the pointer point to the given ostream& but do nothing when it goes out of scope; it gives it a deleter function that does nothing. You can do this without lambdas too, it's just easier for this example.
The simplest thing to do is just bind your reference to an ofstream, and make sure the ofstream lives as long as your object:
class Log
{
std::ofstream byname;
std::ostream& os;
public:
Log(std::ostream& stream = std::cout) : byname(), os(stream) { }
Log(std::string filename) : byname(filename), os(this->byname)
{
if (!os)
// handle errors
}
};
Exception safe, can't leak, and the compiler-generated special member functions are sane.
In my Log/Debug class I find it useful to create a static member variable:
class debug {
public:
...
// Overload operator() for printing values.
template<class Type1>
inline debug&
operator()(const std::string& name1,
const Type1& value1)
{
// Prettify the name/value someway in another inline function.
_stream << print_value(name1, value1) << std::endl;
return *this;
}
private:
...
static std::ostream& _stream;
};
And then in my debug.cc file:
std::ostream& debug::_stream = std::cerr;
You have to initialize the os in the initialize list in the constructors, just as what you did in Log(std::ostream& os = std::cout): os_(os) { }, because os is a reference, which can not be assigned after initialized.
I have an object that I want to be able to stream. But I want to be able to stream it in different ways by using different formats, or should I say ways to describe this object. And I wonder how this is supposed to be solved with streams.
What I want is to be able to use a generic format and use some kind of format adapter to transform the generic format into the preferred format.
I also want to be able to separate the format from the implementation of Item, so I do not have to change Item each time a new format is added or changed.
this code illustrate approximately what I want.
Item item;
std::cout << "generic formatted:" << item;
std::cout << "custom formatted:" << CustomItemFormat() << item;
but this might not be possible or practical.
how is the streaming library intended to be used facing such problems?
Personally I would write a set of formatters.
The formatters have to know the internals of the object they are formatting
but making them friends should not be a big deal.
class X
{ friend std::ostream& operator<<(std::ostream& str,XML_Format const& formatter);
friend std::ostream& operator<<(std::ostream& str,Json_Format const& formatter);
friend std::ostream& operator<<(std::ostream& str,Fred_Format const& formatter);
public: int value() const {return 5;}
};
struct XML__Foram { X const& print; XML_Format(X const& v): print(v) {} };
struct Json_Format { X const& print; Json_Format(X const& v): print(v) {} };
struct Fred_Format { X const& print; Fred_Format(X const& v): print(v) {} };
std::ostream& operator<<(std::ostream& str,XML_Format const& formatter)
{
return str << "<XObj>" << formatter.print.value() << "</XObj>";
}
std::ostream& operator<<(std::ostream& str,Json_Format const& formatter)
{
return str << "{XObj:{" << formatter.print.value() << "}}";
}
std::ostream& operator<<(std::ostream& str,Fred_Format const& formatter)
{
return str << "Killl Kill Kill. Friday 13th";
}
int main()
{
X obj;
std::cout << XML_Format(obj) << std::endl;
}
Yes it's possible, the magic word you're looking for is stream manipulators.
Check out this question: C++ custom stream manipulator that changes next item on stream
You need to write a stream manipulator which stores information in the stream that is then used by operator<<(std::ostream&,const Item&). See the beginning of this answer for how to store user data in a stream.
IOStreams are not very well-suited for this, but you can use a formatting library such as {fmt} that provides better extensibility. For example:
struct Item {
int value;
};
template <>
struct fmt::formatter<Item> {
enum format { generic, custom };
format f = generic;
constexpr auto parse(parse_context &ctx) {
auto it = ctx.begin(), end = ctx.end();
if (it == end) return it;
if (*it == 'g') f = generic;
else if (*it == 'c') f = custom;
else return it;
return ++it;
}
template <typename FormatContext>
auto format(const Item& item, FormatContext &ctx) {
return format_to(ctx.out(), f == generic ? "{}" : "{:x}", item.value);
}
};
Then you can use Item objects with any formatting function such as print:
fmt::print("{}", Item{42}); // Default generic format - value formatted as decimal
fmt::print("{:g}", Item{42}); // Explicit generic format
fmt::print("{:c}", Item{42}); // Custom format - value formatted as hex
Disclaimer: I'm the author of {fmt}.
What is so bad about Item.CustomItemFormat()?
Alternatively there are some design patterns aimed at solving this problem, namely the visitor pattern.
You could also have CustomItemFormat(Item)?
I dont think that asking streams to solve this problem is the right orientation, you should delegate the task of showing itself to the Item class
The more I think about it I am starting to wonder if I am approaching this the wrong way. Perhaps I should have a generic format interface and setting the format for the item, so the item can output itself using this format.
Does this make sense?
Try using the Visitor design pattern:
struct Object_Writer_Interface
{
virtual void write_member_i(int value) = 0;
virtual void write_member_c(char value) = 0;
};
struct Object
{
int i;
char c;
void write(Object_Writer_Interface * p_writer)
{
if (p_writer)
{
p_writer->write_member_i(i);
p_writer->write_member_c(c);
}
}
};
struct Stream_Object_Writer
: public Object_Writer_Interface
{
Stream_Object_Writer(std::ostream& out)
: m_out(out)
{ ; }
void write_member_i(int value)
{
m_out << i << '\n';
}
void write_member_c(char c)
{
m_out << "'" << c << "'\n";
}
std::ostream& m_out;
};
int main(void)
{
Object o;
o.i = 5;
o.c = 'M';
// Create a writer for std::cout
Stream_Object_Writer writer(std::cout);
// Write the object to std::cout using the writer
o.write(&writer);
return EXIT_SUCCESS;
}
With this design, to write the objects to a socket, you derive a class from Object_Writer_Interface to handle the socket. And similarly if you want to serialize the Object.
I'm currently using this technique for writing objects to GUI list boxes, database records and Xml files. Unlike the technique for overloading operator <<, I didn't have to modify the principle class when developing new Writers.