473,405 Members | 2,444 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,405 software developers and data experts.

Using temporary std::stream object

Hello,

In main(), the first output API is what I try to achieve. Unfortunately
it fails, printing first string as pointer instead of human readable
message. Tried to initialize str(""), set new buffer etc, but nothing
worked.

Ideas? Also might use another internal construct, only API is needed
and requirement to reuse existing std::ostream inserters.

App itself:
#include <iostream>
#include <sstream>
class printer
{
public:

void print (const std::string &s) {
std::cout << s << std::endl;
}
};
class stream: public std::ostringstream
{
public:

stream (printer &p): std::ostringstream(), printer_(p) {
// gets stored correctly
*this << "*** ";
}

~stream () {
printer_.print(str());
}

std::ostream &
operator* () {
return *this;
}
private:

printer &printer_;
};
int
main ()
{
printer p;

// want to achieve this but:
// prints address of string instead of "first"
stream(p) << "first" << " fails";

// works because first inserted object is not printed
stream(p) << std::flush << "ok 1";

// works because stream object is used through 'operator*'
// can be any other method returning this or *this
*stream(p) << "ok 2";

return 0;
}

May 19 '06 #1
3 3010
I've found some solutions, but my understanding of what is happening
is limited. As I see it, g++ won't consider the temporary stream
objects as viable arguments to functions taking 'stream&', just
'stream' or 'const stream&'. Thus the only insertion operators
considered are the member insertion operators (since the binary
variety all take non-const refs). Why are the member insertion
operators valid? I don't know. As a result,
'ostream::operator<<(void const*)' gets picked as the function used in
'stream(p) << "first"'.

You don't have this issue in other uses of '<<'.
'ostream::operator<<(void const*)' returns an ostream&, so
'operator<<(ostream&, const char *)' gets called for ' << " fails"'.
Similarly, '*stream(p) << "ok 2"' works because 'stream::operator*()'
returns an ostream&. '*this << "*** "' works because '*this' is a
'stream&'. &c.

What to do? I tried a couple alterations of your current
implementation. They all started with the idea of adding an
operator<< and most ended with const abuse. The simplest was to never
use a temporary 'stream', but this may not work for your application.

The shortest was to add:

std::ostream& operator<<(const stream& streme, const char* str) {
return (* const_cast<stream&>(streme)) << str;
}

I also tried:

std::ostream& operator<<(stream streme, const char* str) {
return (*streme) << str;
}

but it required more code than the first example above, and messy code
at that. For example, inserting into a local 'stream' object would
create a temporary 'stream', both of which would print. I created a
method to cancel a 'stream', but it needed to be called on a 'const
stream&', so I used a mutable member of 'stream'... It was
conceptually hideous. If you are only going to use temporary streams,
it might work for you; in this case, the only other thing you need to
add is a copy constructor.

You may be able to find a way of writing a stream::operator<<(const
char*). Everytime I tried, g++ would complain that, according to ISO
C++, 'stream::operator<<(const char*)' and 'operator<<(ostream&, const
char*)' were ambiguous. If 'stream' didn't inherit from
'ostringstream', this would definitely work, but you'd have to define
the various '<<(stream&, ARG2)' and '<<(ARG)' methods.

I tried to think of a way to use a factory method (called
stream::make) rather than a constructor to create streams (such an
approash shouldn't abuse constness), but couldn't do it without
dynamically created objects. Throw in smart pointers and it would
work with minimal changes to the API (use stream::make rather than
stream::stream), but seems heavy handed.

I hope something here will work or set you off in the direction of a
workable solution.
May 21 '06 #2
Messed with code myself also and went quite similar direction as you
did: create new stream inserter that will return std::ostream, on which
following inserters will continue to work :)

Resolved ambiguity by making inserter member operator, that calls
external inserter and returns result stream.

Final solution:
#include <iostream>
#include <sstream>
class printer
{
public:

void
print (const std::string &s) {
std::cout << s << std::endl;
}
};
class stream: public std::ostringstream
{
public:

stream (printer &p): printer_(p) {}
~stream () {
printer_.print(str());
}
template <typename T>
std::ostream &
operator<< (const T &t) {
return static_cast<std::ostream &>(*this) << t;
}
private:

printer &printer_;
};

int
main ()
{
printer p;
stream(p) << "now" << " works " << "well";

return 0;
}

May 21 '06 #3
In message <rn********************************@4ax.com>, Kanenas
<kanenas_@t_comcast_d.t_net> writes
I've found some solutions, but my understanding of what is happening
is limited. As I see it, g++ won't consider the temporary stream
objects as viable arguments to functions taking 'stream&', just
'stream' or 'const stream&'.
It's not just g++. No conformant compiler will, because you'd be binding
a temporary to a non-const reference, which is forbidden. Thus the only insertion operators
considered are the member insertion operators (since the binary
variety all take non-const refs). Why are the member insertion
operators valid? I don't know.
Because calling a non-const member function of a temporary doesn't bind
it to a reference.
As a result,
'ostream::operator<<(void const*)' gets picked as the function used in
'stream(p) << "first"'.

You don't have this issue in other uses of '<<'.
'ostream::operator<<(void const*)' returns an ostream&, so
'operator<<(ostream&, const char *)' gets called for ' << " fails"'.
Similarly, '*stream(p) << "ok 2"' works because 'stream::operator*()'
returns an ostream&. '*this << "*** "' works because '*this' is a
'stream&'. &c.

What to do? I tried a couple alterations of your current
implementation. They all started with the idea of adding an
operator<< and most ended with const abuse. The simplest was to never
use a temporary 'stream', but this may not work for your application.


How about giving your stream class a function (or operator()) that
returns a reference to itself?

Then you can call it using e.g.

stream(p)() << "hello";

--
Richard Herring
May 22 '06 #4

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

Similar topics

8
by: pt | last post by:
Hallo, i wonder how it is going to be of this code below regarding of the return of temporary object. Prototypes: =========== bool Activation(TCHAR *c); std::basic_string<TCHAR> GetFile();
15
by: Dave Rahardja | last post by:
Hi all, Although the following definition is legal: const int& i = 5; ....and that the lifetime of the temporary variable to which i refers is identical to i itself, why would anyone want...
11
by: Marco Wedekind | last post by:
Hello all, I have a strange compiler behaviour with this code: ---- Begin of code snippet ---- class Base { public: static unsigned int ClassId();
2
by: xllx.relient.xllx | last post by:
Assuming compiler optimizations are set to off, specifically to not allow the compiler to elide the copy constructor, would the following hold true?: If you call a function with an user-defined...
4
by: Jess | last post by:
Hello, If a function's signature is: T f(); and it returns its result (of type T) by value, then the result will be copied into a temporary place, as a temporary object. If it is a...
5
by: Dario Menendez | last post by:
Is it possible to throw a reference to a temporary object? Will the temporary object be copied one or more times? See following example: struct my_exception { my_exception(int i) : i_(i) {}...
1
by: subramanian100in | last post by:
Consider the following: int x; int y; int z; (x+y) = z; For this statement, I get the following error with g++ compiler: error: non-lvalue in assignment Suppose I have a class Test and x,...
3
by: subramanian100in | last post by:
Consider the code fragment: vector<intcontainer; container.insert(container.begin(), 10); int& ref = *--container.end(); From this, it looks like we can apply prefix decrement operator to...
4
by: cxf | last post by:
class A{ public: A() { func(0); }; virtual void func(int data) { printf("A1 :%d\n",data); }
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
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: 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
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
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
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...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

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.