473,395 Members | 1,763 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

defining a custom output facility

I'd like to create a "custom output facility". In other words, I want
an object whose use is similar to std::cout/std::cerr, but offers more
flexibility. Instead of simply writing the parameter to stdout/stderr,
I'd like it to write to stdout, to a file, and/or call a logging
function.

So my output function might look something like this:

OutputFacility& OutputFacility::put(const std::string& s) {
cout << s; // print to stdout
write_to_logfile(s); // also calling logging function
return *this;
}

Now I can define the << operator to be an alias for put().

My question is: do I have to define put() for every type of input I
expect to print? I.e., I'd like this to work with all primitive types,
int, char, double, float, etc.

Right now I'm thinking that the OutputFacility class could have a
std::ostringstream as a private member; every version of
OutputFacility::put() would just in turn call the ostringstream put()
method, THEN call the actual output functions (e.g. write_to_logfile()).

It seems like there should be a simpler method of defining my put
method, i.e. instead of overloading it and defining it multiple times,
if I could just define it once with a "magical" parameter that means
"take anything that can be converted to a string".

Thanks for any advice!
Matt

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #1
12 3169
On Tue, 13 Jan 2004 20:11:51 GMT, Matt Garman <fa**@not-real.bogus> wrote:
OutputFacility& OutputFacility::put(const std::string& s) {
cout << s; // print to stdout
write_to_logfile(s); // also calling logging function
return *this;
}

My question is: do I have to define put() for every type of input I
expect to print? I.e., I'd like this to work with all primitive types,
int, char, double, float, etc.


It looks like I can get away with the following:

template <class T> OutputFacility& OutputFacility::put(const T& x) {
std::ostringstring os;
os << x;
cout << os.str();
write_to_logfile(os.str());
return *this;
}

This seems to get me "close" to what I want to do. It works for
strings, c-style strings (char arrays), and integers. But it doesn't
recognize std::endl and it truncates the fraction part of a float.

Any thoughts?

Thanks again!
Matt

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #2
Matt Garman wrote:
I'd like to create a "custom output facility". In other words, I want
an object whose use is similar to std::cout/std::cerr, but offers more
flexibility. Instead of simply writing the parameter to stdout/stderr,
I'd like it to write to stdout, to a file, and/or call a logging
function.

So my output function might look something like this:

OutputFacility& OutputFacility::put(const std::string& s) {
cout << s; // print to stdout
write_to_logfile(s); // also calling logging function
return *this;
}

Now I can define the << operator to be an alias for put().

My question is: do I have to define put() for every type of input I
expect to print? I.e., I'd like this to work with all primitive types,
int, char, double, float, etc.

Right now I'm thinking that the OutputFacility class could have a
std::ostringstream as a private member; every version of
OutputFacility::put() would just in turn call the ostringstream put()
method, THEN call the actual output functions (e.g. write_to_logfile()).

It seems like there should be a simpler method of defining my put
method, i.e. instead of overloading it and defining it multiple times,
if I could just define it once with a "magical" parameter that means
"take anything that can be converted to a string".

Thanks for any advice!
Matt

template< typename T >
OutputFacility&
operator << ( OutputFacility& out, T const& out )
{
return out.put( lexical_cast< std::string >( s ) );
}

http://www.boost.org/libs/conversion...m#lexical_cast

Jul 22 '05 #3
Matt Garman wrote:
This seems to get me "close" to what I want to do. It works for
strings, c-style strings (char arrays), and integers. But it doesn't
recognize std::endl and it truncates the fraction part of a float.


std::endl is specific to ostreams. It is not declared as a newline, but
rather a function that writes a newline, then flushes the ostream.
Since your OutputFacility class isn't an ostream, it won't work.

I don't see the float truncation, it works for me. Post a compilable
example.

--
Andrew
Jul 22 '05 #4
On Tue, 13 Jan 2004 20:11:51 GMT in comp.lang.c++, Matt Garman
<fa**@not-real.bogus> was alleged to have written:
I'd like to create a "custom output facility". In other words, I want
an object whose use is similar to std::cout/std::cerr, but offers more
flexibility. Instead of simply writing the parameter to stdout/stderr,
I'd like it to write to stdout, to a file, and/or call a logging
function.


C++ streams are constructed as two layers. The upper layer, derived
from iostream, is concerned with formatting objects to and from a
character representation. The lower level, derived from streambuf, is
concerned with transferring those characters to and from some
receptacle.

It is usually a mistake to try to create a customized stream class by
deriving from the stream classes. What you want instead is to derive
from streambuf, and construct a stream using your custom streambuf.

See the examples on Dietmar Kuehl's web site
http://www.informatik.uni-konstanz.d.../c++/iostream/


Jul 22 '05 #5

"David Harmon" <so****@netcom.com> wrote in message
news:40**************@news.west.earthlink.net...
On Tue, 13 Jan 2004 20:11:51 GMT in comp.lang.c++, Matt Garman
It is usually a mistake to try to create a customized stream class by deriving from the stream classes. What you want instead is to derive from streambuf, and construct a stream using your custom streambuf.

See the examples on Dietmar Kuehl's web site
http://www.informatik.uni-konstanz.d.../c++/iostream/


I've written a library to make defining new streambufs easy. See
http://groups.yahoo.com/group/boost/...treams_lib.zip (you have
to sign up with boost to access it, I think.)

Jonathan
Jul 22 '05 #6
On Tue, 13 Jan 2004 20:44:47 GMT, Andrew Taylor <at*****@its.to> wrote:
std::endl is specific to ostreams. It is not declared as a newline,
but rather a function that writes a newline, then flushes the ostream.
Since your OutputFacility class isn't an ostream, it won't work.
That makes sense, I forgot that endl is actually a function.

So in the example I posted here, I could create my own endl function to
achieve similar functionality, right?
I don't see the float truncation, it works for me. Post a compilable
example.


I was mistaken; it appears to be a formatting issue. In other words, I
tried it with more floats, and found that it's only printing a certain
number of digits (regardless of the decimal location).

Thank you!
Matt

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #7
Matt Garman wrote:

On Tue, 13 Jan 2004 20:44:47 GMT, Andrew Taylor <at*****@its.to> wrote:
std::endl is specific to ostreams. It is not declared as a newline,
but rather a function that writes a newline, then flushes the ostream.
Since your OutputFacility class isn't an ostream, it won't work.


That makes sense, I forgot that endl is actually a function.

So in the example I posted here, I could create my own endl function to
achieve similar functionality, right?


You could.
But you are still doing the whole thing the wrong way.
The right way is to write a new stream buffer class
and make a standard stream use it.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #8
On Thu, 15 Jan 2004 18:56:43 +0100, Karl Heinz Buchegger
<kb******@gascad.at> wrote:
So in the example I posted here, I could create my own endl function
to achieve similar functionality, right?


But you are still doing the whole thing the wrong way. The right way
is to write a new stream buffer class and make a standard stream use
it.


I guess I don't really understand the underlying principle(s) behind
this method. I looked over the example on Dietmar Kuehl's website (as
suggested in another post), but didn't really "get it". I think I'm
missing some more fundamental concept(s) here :)

Or perhaps I'm looking at it too much from a "vanilla" C perspective. I
mean, if I was doing this in C, I'd probably just have a function (or
possibly even a #define macro) that had a printf() like syntax, but does
the job of printf() plus writes to a logfile, to a window, etc.

I certainly want to do it the right way, though! Does anyone happen to
have any more links that explain this in greater detail?

Thanks again!
Matt

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #9
Matt Garman wrote:

On Thu, 15 Jan 2004 18:56:43 +0100, Karl Heinz Buchegger
<kb******@gascad.at> wrote:
So in the example I posted here, I could create my own endl function
to achieve similar functionality, right?
But you are still doing the whole thing the wrong way. The right way
is to write a new stream buffer class and make a standard stream use
it.


I guess I don't really understand the underlying principle(s) behind
this method. I looked over the example on Dietmar Kuehl's website (as
suggested in another post), but didn't really "get it". I think I'm
missing some more fundamental concept(s) here :)


The thing is:

The stream object itself is responsible for proper formatting.
The stream buffer object inside the stream is reponsible for bringing
the already formatted data on its way, it's the transportation layer.

You want to change a string in the behaviour of the transportation
layer, thus your approach should be to write a customized stream buffer
and make the stream use that instead of the one it was born with.
Or perhaps I'm looking at it too much from a "vanilla" C perspective. I
mean, if I was doing this in C, I'd probably just have a function (or
possibly even a #define macro) that had a printf() like syntax, but does
the job of printf() plus writes to a logfile, to a window, etc.
If the system is designed flexible (with C++ it is, with C it is not), then
there would be some sort of hook in printf, which allows you to get a grasp
at the string printf produces internally before printf sends this string to the
device. In this way you don't need to change any printf calls but just
hook into it, and do whatever you want with the printf generated string.

With printf this is not possible, with C++ streams it is. In fact it
is specifically designed to be that way.

I certainly want to do it the right way, though! Does anyone happen to
have any more links that explain this in greater detail?


http://www.google.com
"streambuf custom"

http://cpptips.hyperformix.com/cpptips/tee_strm
http://www.phenix.bnl.gov/~phoncs/on...ation/Message/
http://www.codeproject.com/vcpp/stl/zipstream.asp

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #10
On Fri, 16 Jan 2004 13:02:45 +0100, Karl Heinz Buchegger
<kb******@gascad.at> wrote:
You want to change a string in the behaviour of the transportation
layer, thus your approach should be to write a customized stream
buffer and make the stream use that instead of the one it was born
with.
Okay, I think I'm starting to get it :) Thank you!

Since I want my custom output facility to write to stdout AND a log (or
window or whatever), does that mean that my custom streambuf's
implementation will write to stdout? It seems like I would be
duplicating what the standard library already does. (In other words, is
there a way to say "do what you already do, AND do these other things"?)

Let me re-iterate just to make sure my understanding is correct:

- stream object (e.g. cout) formats data
- stream object passes formatted data to stream buffer
- stream buffer object delivers data to its destination (e.g.
stdout, logfile, window, etc)
there would be some sort of hook in printf, which allows you to get a
grasp at the string printf produces internally before printf sends
this string to the device. In this way you don't need to change any
printf calls but just hook into it, and do whatever you want with the
printf generated string.


That's exactly what sprintf() (and snprintf() on some systems)
does---formats a string and puts it in a buffer. But that opens you up
to all kinds of potential buffer overrun problems. It's a lot of work
to make sure this is done safely. (That's why I'm using c++!)

Thanks again for your help and patience,
Matt

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #11
Matt Garman wrote:

Since I want my custom output facility to write to stdout AND a log (or
window or whatever), does that mean that my custom streambuf's
implementation will write to stdout?
typically yes.
But wait: when you tell the stream object to use a different stream
buffer, you get a hold on the stream buffer actually used by the
stream. So you simply could forward all output to the original stream
buffer AND process it on your own.

Let me re-iterate just to make sure my understanding is correct:

- stream object (e.g. cout) formats data
- stream object passes formatted data to stream buffer
- stream buffer object delivers data to its destination (e.g.
stdout, logfile, window, etc)
yep.
there would be some sort of hook in printf, which allows you to get a
grasp at the string printf produces internally before printf sends
this string to the device. In this way you don't need to change any
printf calls but just hook into it, and do whatever you want with the
printf generated string.


That's exactly what sprintf() (and snprintf() on some systems)
does---formats a string and puts it in a buffer. But that opens you up
to all kinds of potential buffer overrun problems. It's a lot of work
to make sure this is done safely. (That's why I'm using c++!)


OK.
So with that analogy an output operation in a stream does something
like that:

void DoOutput( ..... )
char buffer[whatever];
sprintf( buffer, ..... );
puts( buffer );
}

Throughout your program you always use DoOutput() instead of printf().
If you need to retarget the output, you add the retargeting by
replacing the puts() with something else.
In the above, the puts() would be the equivalent to the stream buffer
object (and of course the whole thing wrapped in a class with some
nicer syntax for using and getting rid of the buffer overflow problem,
etc. But that's not the point right now). For retargeting the output
you replace the stream buffer with something else. And in the same
sense as in the DoOutput() solution the caller of this function doesn't
notice anything of the retargeting, the user of a stream object doesn't
notice anything when the stream buffer is replaced. For him everything
stays the same, even custom operator<< or operator>> work as they ever did.
Only the output is retargeted to somwehere else.

--
Karl Heinz Buchegger
kb******@gascad.at
Jul 22 '05 #12
Okay, thank you for all the verbose feedback! I think I finally
understand the concepts.

So what if I were to take it a step further, and say that my custom
output facility should be able to write to any number of media? In
other words, combine a streambuf with a vector?

I did just that in the code below (tested with g++ under Linux). Is
what I did the "best" way to solve that problem?

Note that I'd actually write a convenience wrapper class for ostream as
well, just to easily facilitate adding and removing streambufs.

Thanks again for all the help!
Matt

#include <iostream>
#include <fstream>
#include <streambuf>
#include <vector>

class streambufvec : public std::streambuf {
public:
typedef std::char_traits<char> traits_type;
typedef traits_type::int_type int_type;
typedef std::vector< std::streambuf* > streambufvec_t;

streambufvec()
{ streambufs.push_back(std::cout.rdbuf()); }

streambufvec(streambufvec_t sbvec)
{ streambufs.insert(streambufs.end(),
sbvec.begin(), sbvec.end()); }

streambufvec(std::streambuf* sb)
{ streambufs.push_back(sb); }

virtual ~streambufvec()
{ streambufs.clear(); }

void push_back(std::streambuf* sb)
{ streambufs.push_back(sb); }

protected:
inline int_type overflow(int_type c)
{
streambufvec_t::iterator ii;
for (ii=streambufs.begin(); ii!=streambufs.end(); ++ii) {
if (traits_type::eof() == (*ii)->sputc(c)) {
return traits_type::eof();
}
}
return c;
}

private:
streambufvec_t streambufs;
};
int main(int argc, char** argv)
{
std::ofstream file1("file1.txt");
std::ofstream file2("file2.txt");
std::ofstream file3("file3.txt");

streambufvec sbvec;
sbvec.push_back(file1.rdbuf());
sbvec.push_back(file2.rdbuf());
sbvec.push_back(file3.rdbuf());

sbvec.push_back(std::cerr.rdbuf());

std::ostream of(&sbvec);

of << "Hello, world!" << std::endl;

return 0;
}

--
Matt Garman
email at: http://raw-sewage.net/index.php?file=email
Jul 22 '05 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

0
by: Brian van den Broek | last post by:
Hi all, IDLE refuses to launch, and I believe it is because I attempted to define a custom key-binding that it doesn't like. I was recently defining a custom keybinding in IDLE 1.1 under...
3
by: Paul Bowman | last post by:
Hi All Java has a facility where you can send output to a DOS window using System.out.println. This is useful while developing as you can see what it going in your code. Does .Net provide a...
0
by: Samir Patel | last post by:
Hi Everybody hai i am fine what about all of u? i have a problem regarding to ASP.NET custom control , can anybody help me? my problem is when i placed my custom control on page at design...
19
by: Dales | last post by:
I have a custom control that builds what we refer to as "Formlets" around some content in a page. These are basically content "wrapper" sections that are tables that have a colored header and...
5
by: Sadeq | last post by:
Is it possible to define custom attributes for arrays? And if so, how can I retrieve them? I mean I want to define sth like: int MyArray; and then retrieve the value of the custom...
17
by: rdemyan | last post by:
My app creates a building report. My users have requested that I provide functionality to e-mail these "building reports" to building managers once a month. So assuming that I have the...
1
by: rn5a | last post by:
I have created a custom control button which when clicked displays a message in the JavaScript alert dialog. I could successfully compile the VB class file into a DLL & also could add it to the...
1
by: rn5a | last post by:
I want to create a custom control that encapsulates a Button & a TextBox. When the Button is clicked, the user is asked a question using JavaScript confirm (which shows 2 buttons - 'OK' &...
0
by: rn5a | last post by:
A custom control is derived from the WebControl class & encapsulates a TextBox & a Button. When the Button is clicked, the user is shown the JavaScript confirm dialog with the 'OK' & 'Cancel'...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.