472,790 Members | 1,339 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 472,790 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 1532
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: Rina0 | last post by:
Cybersecurity engineering is a specialized field that focuses on the design, development, and implementation of systems, processes, and technologies that protect against cyber threats and...
3
isladogs
by: isladogs | last post by:
The next Access Europe meeting will be on Wednesday 2 August 2023 starting at 18:00 UK time (6PM UTC+1) and finishing at about 19:15 (7.15PM) The start time is equivalent to 19:00 (7PM) in Central...
0
by: erikbower65 | last post by:
Using CodiumAI's pr-agent is simple and powerful. Follow these steps: 1. Install CodiumAI CLI: Ensure Node.js is installed, then run 'npm install -g codiumai' in the terminal. 2. Connect to...
0
linyimin
by: linyimin | last post by:
Spring Startup Analyzer generates an interactive Spring application startup report that lets you understand what contributes to the application startup time and helps to optimize it. Support for...
0
by: kcodez | last post by:
As a H5 game development enthusiast, I recently wrote a very interesting little game - Toy Claw ((http://claw.kjeek.com/))。Here I will summarize and share the development experience here, and hope it...
0
by: Rina0 | last post by:
I am looking for a Python code to find the longest common subsequence of two strings. I found this blog post that describes the length of longest common subsequence problem and provides a solution in...
5
by: DJRhino | last post by:
Private Sub CboDrawingID_BeforeUpdate(Cancel As Integer) If = 310029923 Or 310030138 Or 310030152 Or 310030346 Or 310030348 Or _ 310030356 Or 310030359 Or 310030362 Or...
0
by: Mushico | last post by:
How to calculate date of retirement from date of birth
2
by: DJRhino | last post by:
Was curious if anyone else was having this same issue or not.... I was just Up/Down graded to windows 11 and now my access combo boxes are not acting right. With win 10 I could start typing...

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.