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

behaviour change in operator<<

I found a change in the following code, that behaved
correctly in VC++ 6.

#include <strstream>
using namespace std;
void main()
{
char x[100];
ostrstream(x, 100) << "pippo" << "pluto" << ends;
// here x contains "004400C8pluto"
}

Clearly,

basic_ostream::operator<<(const void*)
have been called, instead of
basic_ostream::operator<<(const char*).

Some change in scoping rule (due to the introduction of
Koenig Lookup) justify this change?

Many Thanks for your attention.

Nov 16 '05 #1
3 1564
Carlo Capelli wrote:
I found a change in the following code, that behaved
correctly in VC++ 6.

#include <strstream>
using namespace std;
void main()
{
char x[100];
ostrstream(x, 100) << "pippo" << "pluto" << ends;
// here x contains "004400C8pluto"
}

Clearly,

basic_ostream::operator<<(const void*)
have been called, instead of
basic_ostream::operator<<(const char*).

Some change in scoping rule (due to the introduction of
Koenig Lookup) justify this change?

Many Thanks for your attention.


It's not a bug. There is a member output operator for void*, but the char*,
signed char*, and unsigned char* output operators are non-members whose
first parameter is a non-const ostream&. The compiler is choosing the member
operator, because you can call member functions through temporary objects,
e.g. X().f(), or here, ostream().operator<<("pippo"), but you can't bind
temporaries to non-const references, which eliminates the non-member
operators. So:

ostrstream(x, 100) << "pippo" << "pluto" << ends;

calls the operator<<(const void*) member and stores a pointer value[1],
while:

ostrstream os(x, 100);
os << "pippo" << "pluto" << ends;

calls the non-member operator<<(ostream&, const char*) and stores the
strings.

The craziest thing is that this is apparently the way it's supposed to work.
The non-member operators<< are rejected in the first case as non-viable,
because selecting them would require binding a temporary to a non-const
reference, leaving the member operator<<(const void*) to handle the output
of the string literal. FWIW, I'm not convinced it makes sense to eliminate
functions from overload resolution based on the reference binding issue, but
that's what the standard says.

[1] The string "pluto" is stored after the address of "pippo", because
operator<< returns ostream&, and there's no problem binding it to the first
parameter of operator<<(ostream&, const char*).

--
Doug Harrison
Microsoft MVP - Visual C++
Nov 16 '05 #2
>From: "Doug Harrison [MVP]" <ds*@mvps.org>
Subject: Re: behaviour change in operator<<
Date: Wed, 13 Aug 2003 13:23:36 -0500
Message-ID: <qr********************************@4ax.com>
References: <0a****************************@phx.gbl>

Carlo Capelli wrote:
I found a change in the following code, that behaved
correctly in VC++ 6.

#include <strstream>
using namespace std;
void main()
{
char x[100];
ostrstream(x, 100) << "pippo" << "pluto" << ends;
// here x contains "004400C8pluto"
}

Clearly,

basic_ostream::operator<<(const void*)
have been called, instead of
basic_ostream::operator<<(const char*).

Some change in scoping rule (due to the introduction of
Koenig Lookup) justify this change?

Many Thanks for your attention.
It's not a bug. There is a member output operator for void*, but the char*,
signed char*, and unsigned char* output operators are non-members whose
first parameter is a non-const ostream&. The compiler is choosing the

memberoperator, because you can call member functions through temporary objects,
e.g. X().f(), or here, ostream().operator<<("pippo"), but you can't bind
temporaries to non-const references, which eliminates the non-member
operators. So:

ostrstream(x, 100) << "pippo" << "pluto" << ends;

calls the operator<<(const void*) member and stores a pointer value[1],
while:

ostrstream os(x, 100);
os << "pippo" << "pluto" << ends;

calls the non-member operator<<(ostream&, const char*) and stores the
strings.

The craziest thing is that this is apparently the way it's supposed to work.The non-member operators<< are rejected in the first case as non-viable,
because selecting them would require binding a temporary to a non-const
reference, leaving the member operator<<(const void*) to handle the output
of the string literal. FWIW, I'm not convinced it makes sense to eliminate
functions from overload resolution based on the reference binding issue, butthat's what the standard says.

[1] The string "pluto" is stored after the address of "pippo", because
operator<< returns ostream&, and there's no problem binding it to the first
parameter of operator<<(ostream&, const char*).

--
Doug Harrison
Microsoft MVP - Visual C++


Actually there is a bug here :-( You can only call const member functions
on a temporary
object of a class type - and as all the ostream::operator<< functions are
non-const and all the
global operator<< require a ostream& as the first parameter the compiler
should not be able to
call any of the available functions. This code should not compile: I quick
check with the Comeau
indicates that the EDG compiler does indeed reject this code.

I've added the issue to our bug-database.

--
Jonathan Caves, Visual C++ Team
This posting is provided AS IS with no warranties, and confers no rights.

Nov 16 '05 #3
>From: "Doug Harrison [MVP]" <ds*@mvps.org>
Subject: Re: behaviour change in operator<<
Date: Wed, 13 Aug 2003 14:52:21 -0500
Message-ID: <sq********************************@4ax.com>
References: <0a****************************@phx.gbl> <qr********************************@4ax.com>
<tm**************@cpmsftngxa06.phx.gbl>
Jonathan Caves [MSFT] wrote:
Actually there is a bug here :-( You can only call const member functions
on a temporary
object of a class type
Perhaps strangely, that's incorrect. Things like this are perfectly legal:

struct X
{
X& operator=(const X&);
};

void f()
{
X() = X();
}

The non-const reference binding issue is solely responsible for this
weirdness:

void g(X&);

void h()
{
g(X()); // 1. Bad!
g(X() = X()); // 2. Fine!
}

Now add:

void g(const X&);

to the above and try again. You'll see that (1) now compiles, but note that
it calls the new overload which takes a const X&. On the other hand, (2)
calls the original g which takes plain X&. This is what I find hard to
justify for class types. It seems to me that a non-const X should bind to
X&, whether it's an rvalue or not. IIRC, when I experimented with this in
VC6 a couple of years ago, that's the rule VC6 implemented, while still
forbidding the binding for built-in types. I think that makes a lot of
sense, but it isn't standard. (NB: When using VC, compile the fragments

with-Za to get standard conformant behavior, which is what I've assumed above.)

Sigh: you are correct Doug: somehow in reducing the test case to a more
simple example I
changed it enough that the code did not compile. I admit the behavior does
appear strange
but I've convinced myself that it is allowed by the Standard. So you are
correct we don't
have a bug.
I've added the issue to our bug-database.


I think you can unbug it. :)


It's been debugged :-)

--
Jonathan Caves, Visual C++ Team
This posting is provided AS IS with no warranties, and confers no rights.

Nov 16 '05 #4

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

Similar topics

4
by: franky.backeljauw | last post by:
Hello, I have a problem with using a copy constructor to convert an object of a templated class to object of another templated class. Let me first include the code (my question is below): ...
3
by: Victor Irzak | last post by:
Hello, I have an ABC. it supports: ostream & operator << I also have a derived class that supports this operator. How can I call operator << of the base class for derived object??? Is it...
3
by: Alex Vinokur | last post by:
Member operators operator>>() and operator<<() in a program below work fine, but look strange. Is it possible to define member operators operator>>() and operator<<() that work fine and look...
3
by: Sensei | last post by:
Hi. I have a problem with a C++ code I can't resolve, or better, I can't see what the problem should be! Here's an excerpt of the incriminated code: === bspalgo.cpp // THAT'S THE BAD...
14
by: lutorm | last post by:
Hi everyone, I'm trying to use istream_iterators to read a file consisting of pairs of numbers. To do this, I wrote the following: #include <fstream> #include <vector> #include <iterator> ...
4
by: bluekite2000 | last post by:
Here A is an instantiation of class Matrix. This means whenever user writes Matrix<float> A=rand<float>(3,2);//create a float matrix of size 3x2 //and fills it up w/ random value cout<<A; the...
2
by: Harry | last post by:
Hi all, I am writing a logger program which can take any datatype. namespace recordLog { enum Debug_Level {low, midium, high}; class L { std::ofstream os; Debug_Level cdl; const...
4
by: Amadeus W. M. | last post by:
What is the difference between friend ostream & operator<<(ostream & OUT, const Foo & f){ // output f return OUT; } and template <class X>
6
by: johnmmcparland | last post by:
Hi all, when I write a subclass, can I inherit its superclass' << operator? As an example say we have two classes, Person and Employee. class Person has the << operator; /**
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?
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
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
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...
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,...
0
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new...

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.