473,396 Members | 1,832 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,396 software developers and data experts.

Calling constructors and temporary objects

(No, I'm *not* trying to call a constructor from another constructor!)

I have this class:

class P : public std::stringstream
{
public:
~P() { std::cout << str(); }
};

That is, it behaves like a stringstream, but on destruct it prints
itself. This allows me to do this:

{
P p;
p << "Hello, world!";
}

....and I get 'Hello world!' on stdout.

However, if instead I do this:

P() << "Hello world!";

....I get '0x12345678' instead (that is, some random hex number).

Obviously what's happening is that it's not finding the const char*
iostream method on P, and is falling back to the void* one; but I don't
understand why. The temporary P instance is getting created and
destructed at the appropriate points, but it's behaving as if it's lost
some of its stringstream methods.

I use this idiom extensively for various printers and loggers and so on;
they all work fine. This is the first time I've tried it with a subclass
of stringstream, though; all the others have delegated to an embedded
instance of stringstream rather than subclassing it. I thought I'd save
myself some typing this way. But why doesn't it work? More importantly,
why is it not working in this really bizarre fashion?

--
┌─── dg*cowlark.com ───── http://www.cowlark.com ─────
│ "I have always wished for my computer to be as easy to use as my
│ telephone; my wish has come true because I can no longer figure out
│ how to use my telephone." --- Bjarne Stroustrup
Jun 27 '08 #1
4 1702
David Given wrote:
(No, I'm *not* trying to call a constructor from another constructor!)

I have this class:

class P : public std::stringstream
{
public:
~P() { std::cout << str(); }
};

That is, it behaves like a stringstream, but on destruct it prints
itself. This allows me to do this:

{
P p;
p << "Hello, world!";
}

...and I get 'Hello world!' on stdout.

However, if instead I do this:

P() << "Hello world!";

...I get '0x12345678' instead (that is, some random hex number).

Obviously what's happening is that it's not finding the const char*
iostream method on P, and is falling back to the void* one; but I don't
understand why.
The reason is that one is a member function (the one that is found) and the
other is a free function that is rejected as a match because the compiler
is not allowed to bind the non-const stream reference to the temporary P().

The temporary P instance is getting created and
destructed at the appropriate points, but it's behaving as if it's lost
some of its stringstream methods.

I use this idiom extensively for various printers and loggers and so on;
they all work fine. This is the first time I've tried it with a subclass
of stringstream, though; all the others have delegated to an embedded
instance of stringstream rather than subclassing it. I thought I'd save
myself some typing this way. But why doesn't it work? More importantly,
why is it not working in this really bizarre fashion?
The culprit is clause [8.5.3/5].

Note: your case is similar to this

std::vector<int>().swap( my_vector ); // legal
swap( std::vector<int>(), my_vector ); // not legal
my_vector.swap( std::vector<int>() ); // not legal

The difference is that the compiler finds a match using a conversion to
void* after all illegal readings have been ruled out. It doesn't really
make all that much sense, but this is the state of affairs in C++.
Best

Kai-Uwe Bux
Jun 27 '08 #2
Kai-Uwe Bux wrote:
[...]
The reason is that one is a member function (the one that is found) and the
other is a free function that is rejected as a match because the compiler
is not allowed to bind the non-const stream reference to the temporary P().
[...]
The culprit is clause [8.5.3/5].
If I've understood this correctly, this is all due to not being able to
initialise a non-const reference from a temporary, right?

Here's a cleaner test case that fails in the same way (on gcc. MSVC is
quite happy with it, annoyingly enough.)

struct SUPER { };
struct SUB : SUPER { };
SUPER& operator<<(SUPER& s, int i) {}

{ SUB() << 1; }

Given that the temporary goes out of scope at the end of the statement,
I don't see why this restriction is in place --- it should be possible
for the compiler to implicitly bind the reference, pass it to
operator<<(), have operator<<() work on it and then return it, and then
have the temporary get destructed. It's precisely the same semantic as
if I'd used a non-temporary.

So, why isn't this possible, and are there any workarounds? Could I have
SUB automatically cast itself to an object of the right type, for example?

--
┌─── dg*cowlark.com ───── http://www.cowlark.com ─────
│ "I have always wished for my computer to be as easy to use as my
│ telephone; my wish has come true because I can no longer figure out
│ how to use my telephone." --- Bjarne Stroustrup
Jun 27 '08 #3
David Given wrote:
Kai-Uwe Bux wrote:
[...]
>The reason is that one is a member function (the one that is found) and
the other is a free function that is rejected as a match because the
compiler is not allowed to bind the non-const stream reference to the
temporary P().
[...]
>The culprit is clause [8.5.3/5].

If I've understood this correctly, this is all due to not being able to
initialise a non-const reference from a temporary, right?
Yes.
Here's a cleaner test case that fails in the same way (on gcc. MSVC is
quite happy with it, annoyingly enough.)

struct SUPER { };
struct SUB : SUPER { };
SUPER& operator<<(SUPER& s, int i) {}

{ SUB() << 1; }

Given that the temporary goes out of scope at the end of the statement,
I don't see why this restriction is in place --- it should be possible
for the compiler to implicitly bind the reference, pass it to
operator<<(), have operator<<() work on it and then return it, and then
have the temporary get destructed. It's precisely the same semantic as
if I'd used a non-temporary.

So, why isn't this possible, and are there any workarounds? Could I have
SUB automatically cast itself to an object of the right type, for example?
You can make sure that there is always a matching member function:

struct P : public std::stringstream {

template < typename T >
P & operator<< ( T const & t ) {
static_cast< std::stringstream & >( *this ) << t;
return ( *this );
}

~P() { std::cout << str(); }
};
Best

Kai-Uwe Bux
Jun 27 '08 #4
Kai-Uwe Bux wrote:
[...]
You can make sure that there is always a matching member function:

struct P : public std::stringstream {

template < typename T >
P & operator<< ( T const & t ) {
static_cast< std::stringstream & >( *this ) << t;
return ( *this );
}
Hmm. I hadn't thought of using templates in this way. That's very
interesting --- I may be able to apply it to my old delegation approach,
too.

Okay, I'll go and do more investigation. Thanks for the assistance!

--
┌─── dg*cowlark.com ───── http://www.cowlark.com ─────
│ "I have always wished for my computer to be as easy to use as my
│ telephone; my wish has come true because I can no longer figure out
│ how to use my telephone." --- Bjarne Stroustrup
Jun 27 '08 #5

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

Similar topics

42
by: Edward Diener | last post by:
Coming from the C++ world I can not understand the reason why copy constructors are not used in the .NET framework. A copy constructor creates an object from a copy of another object of the same...
4
by: Jerry Krinock | last post by:
I've written the following demo to help me understand a problem I'm having in a larger program. The "main" function constructs a Foo object, and then later "reconstructs" it by calling the...
3
by: rahul8143 | last post by:
hello, I write a following program and have problem in understanding constructors and destructors. #include <iostream.h> class vector { public: double x; double y;
6
by: Justin | last post by:
Hello, first time posting. If I have a base class and a derived class, is there only one way to call the base constructor? i.e. Is this the only way I can call the base constructor...
10
by: John | last post by:
Trying to find out what is essential / optional, I made an extremely simple Class and Module combination to add two numbers. (see below) It appears that an empty constructor is needed n order to...
4
by: Michael | last post by:
Hello, I want to use an object (LowCut) within another object (SampleRateConverter) like it is written as follows: class SampleRateConverter { public: SampleRateConverter( int...
7
by: fakeprogress | last post by:
For a homework assignment in my Data Structures/C++ class, I have to create the interface and implementation for a class called Book, create objects within the class, and process transactions that...
6
by: daveb | last post by:
I'm trying to write some code that calls the constructors of STL containers explicitly, and I can't get it to compile. A sample program is below. One compiler complains about the last two lines...
5
by: bizt | last post by:
Hi, Below I have a simple object / function thing (still getting head round these) declaration: function MyObject() { this.alertMe = function() { alert('hello'); }; this.alertMeAgain() {
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
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:
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
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
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 projectplanning, 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.