Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

compiler bug operator>> matching?

61 views
Skip to first unread message

Norman J. Goldstein

unread,
Feb 13, 2015, 12:43:58 AM2/13/15
to
Here is code that does not compile with
gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC)

#include <iostream>
using namespace std;

istream& operator>>( istream&, const char* );// Line A

namespace
{
class Foo {};
void operator>>( Foo, Foo ); // Line B

void copy( void )
{
const char* memb = "bad";
cin >> memb;
}
}

Here are two ways to make it compile:
1. Move Line A into the namespace, OR
2. Comment out Line B

Here is the compiler error, which I hesitate to include in the posting,
but, for completeness ...

bad.cpp: In function ‘void {anonymous}::copy()’:
bad.cpp:14:12: error: cannot bind ‘std::istream
{aka std::basic_istream<char>}’ lvalue to ‘std::basic_istream<char>&&’
cin >> memb;
^
In file included from /usr/include/c++/4.8.3/iostream:40:0,
from bad.cpp:1:
/usr/include/c++/4.8.3/istream:872:5: error: initializing argument 1
of ‘std::basic_istream<_CharT, _Traits>&
std::operator>>(std::basic_istream<_CharT, _Traits>&&, _Tp&) [with
_CharT = char; _Traits = std::char_traits<char>; _Tp = const char*]’
operator>>(basic_istream<_CharT, _Traits>&& __is, _Tp& __x)
^

Öö Tiib

unread,
Feb 13, 2015, 3:18:52 AM2/13/15
to
It feels the behaviour of compiler is conforming.
It finds 'operator>>( Foo, Foo )' with ordinary lookup and that stops
it from looking into enclosing global namespace of anonymous namespace.
If you comment it out it will look into global namespace too with
ordinary lookup. Also if you move the 'operator>>( istream&, const char*)'
to anonymous then it finds both. With ADL it finds only the operators
in namespace 'std'.

It is considered impractical to declare operators that operate on standard
and fundamental types only in global or user-defined namespaces. It will
often cause issues like you describe.

Paavo Helde

unread,
Feb 13, 2015, 8:18:00 AM2/13/15
to
"Norman J. Goldstein" <nor...@telus.net> wrote in
news:mbk2ug$kdr$1...@speranza.aioe.org:

> Here is code that does not compile with
> gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC)
>
> #include <iostream>
> using namespace std;
>
> istream& operator>>( istream&, const char* );// Line A
>
> namespace
> {
> class Foo {};
> void operator>>( Foo, Foo ); // Line B
>
> void copy( void )
> {
> const char* memb = "bad";
> cin >> memb;
> }
> }
>
> Here are two ways to make it compile:
> 1. Move Line A into the namespace, OR
> 2. Comment out Line B

Yes, this is name lookup problem as described by 嘱 Tiib. To force a
particular overloaded function, spell out the correct name explicitly:

void copy( void )
{
const char* memb = "bad";
::operator>>(cin, memb);
}

Norman J. Goldstein

unread,
Feb 13, 2015, 9:55:56 AM2/13/15
to
On 02/13/2015 05:17 AM, Paavo Helde wrote:
> "Norman J. Goldstein" <nor...@telus.net> wrote in
> news:mbk2ug$kdr$1...@speranza.aioe.org:
>
>> Here is code that does not compile with
>> gcc version 4.8.3 20140911 (Red Hat 4.8.3-7) (GCC)
>>
>> #include <iostream>
>> using namespace std;
>>
>> istream& operator>>( istream&, const char* );// Line A
>>
>> namespace
>> {
>> class Foo {};
>> void operator>>( Foo, Foo ); // Line B
>>
>> void copy( void )
>> {
>> const char* memb = "bad";
>> cin >> memb;
>> }
>> }
>>
>> Here are two ways to make it compile:
>> 1. Move Line A into the namespace, OR
>> 2. Comment out Line B
>
> Yes, this is name lookup problem as described by Öö Tiib. To force a
> particular overloaded function, spell out the correct name explicitly:
>
> void copy( void )
> {
> const char* memb = "bad";
> ::operator>>(cin, memb);
> }
>

Thank you, both. Based on what you said, I "fixed" this by defining the
same operator in the namespace:

namespace
{
istream& operator>>( istream& is, const char* ccp ) {
return ::operator>>( is, ccp ); }
}

The funny thing is, I've been using the global
operator>>( istream&,const char*) ) for years, and it only now posed
this problem.

Paavo Helde

unread,
Feb 13, 2015, 10:00:08 AM2/13/15
to
"Norman J. Goldstein" <nor...@telus.net> wrote in news:mbl394$3ue$1
@speranza.aioe.org:

> Thank you, both. Based on what you said, I "fixed" this by defining the
> same operator in the namespace:
>
> namespace
> {
> istream& operator>>( istream& is, const char* ccp ) {
> return ::operator>>( is, ccp ); }
> }

This can be done easier by:

namespace
{
using ::operator>>;
}

Norman J. Goldstein

unread,
Feb 13, 2015, 12:53:03 PM2/13/15
to
On 02/13/2015 06:59 AM, Paavo Helde wrote:
> "Norman J. Goldstein" <nor...@telus.net> wrote in news:mbl394$3ue$1
> @speranza.aioe.org:
>
>> Thank you, both. Based on what you said, I "fixed" this by defining the
>> same operator in the namespace:
>>
>> namespace
>> {
inline
>> istream& operator>>( istream& is, const char* ccp ) {
>> return ::operator>>( is, ccp ); }
>> }
>
> This can be done easier by:
>
> namespace
> {
> using ::operator>>;
> }
>
OK. I will use the "using", although it pulls in all the operator>>
methods, not just the one with the given signature. But, that is
probably what I want, anyway!

Jens Thoms Toerring

unread,
Feb 13, 2015, 2:42:30 PM2/13/15
to
Norman J. Goldstein <nor...@telus.net> wrote:
> The funny thing is, I've been using the global
> operator>>( istream&,const char*) ) for years, and it only now posed
> this problem.

Apologies for my ignorance, but how can you use an istream
on a 'const char *'? My understanding has been that you
need a reference or a pointer to something non-constant.
Otherwise, how is the stream supposed to write to it (in
your example program even to a string literal, which may
reside in read-only memory)?

Best regards, Jens
--
\ Jens Thoms Toerring ___ j...@toerring.de
\__________________________ http://toerring.de

Pavel

unread,
Feb 14, 2015, 12:35:54 AM2/14/15
to
j...@toerring.de (Jens Thoms Toerring) wrote:
> Norman J. Goldstein <nor...@telus.net> wrote:
>> The funny thing is, I've been using the global
>> operator>>( istream&,const char*) ) for years, and it only now posed
>> this problem.
>
> Apologies for my ignorance, but how can you use an istream
> on a 'const char *'? My understanding has been that you
> need a reference or a pointer to something non-constant.
> Otherwise, how is the stream supposed to write to it (in
> your example program even to a string literal, which may
> reside in read-only memory)?
>
> Best regards, Jens
>
There can be different implementations of operator>>. For example, one might
want to use it to try to extract from the stream and throw away as many
characters as the length of the C string pointed to by the const char* parameter
(in the OP's example specifically, 3 characters). I am curious about the real
intent, too, though.

-Pavel

Norman J. Goldstein

unread,
Feb 14, 2015, 12:23:48 PM2/14/15
to
operator>>( istream&,const char* ) succeeds if the extracted characters
exactly match the supplied const char*. Leading white space is ignored.
I find this a convenient way to help parse a file.

Jens Thoms Toerring

unread,
Feb 14, 2015, 3:05:52 PM2/14/15
to
Thank you for the clarification. It's the one hazards of
operator overloading I see that different people may have
different ideas about what it's meant to do...

Jorgen Grahn

unread,
Feb 14, 2015, 6:03:11 PM2/14/15
to
On Sat, 2015-02-14, Jens Thoms Toerring wrote:
> Norman J. Goldstein <nor...@telus.net> wrote:
>> operator>>( istream&,const char* ) succeeds if the extracted characters
>> exactly match the supplied const char*. Leading white space is ignored.
>> I find this a convenient way to help parse a file.
>
> Thank you for the clarification. It's the one hazards of
> operator overloading I see that different people may have
> different ideas about what it's meant to do...

People complain too much about operator overloading sometimes ... but
here I have to admit I don't like it. If I see "is >> foo", I'm going
to assume it follows the standard pattern -- because a std::istream is
involved, not just because of the ">>".

/Jorgen

--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .

Norman J. Goldstein

unread,
Feb 14, 2015, 6:35:22 PM2/14/15
to
Both of you make good points -- and I agree with you. The risk of name
clash can be mitigated by putting the overloaded operator into a
namespace. As for usefulness, the following code is quite descriptive
for parsing a text file:

string varName;
int varValue;

is >> varName >> ":=" >> varValue >> ";";

if( is.fail() ) { error }

Cheers,
Norm

Jens Thoms Toerring

unread,
Feb 14, 2015, 7:21:55 PM2/14/15
to
Norman J. Goldstein <nor...@telus.net> wrote:
> On 02/14/2015 03:02 PM, Jorgen Grahn wrote:
> > On Sat, 2015-02-14, Jens Thoms Toerring wrote:
> >> Norman J. Goldstein <nor...@telus.net> wrote:
> >>> operator>>( istream&,const char* ) succeeds if the extracted characters
> >>> exactly match the supplied const char*. Leading white space is ignored.
> >>> I find this a convenient way to help parse a file.
> >>
> >> Thank you for the clarification. It's the one hazards of
> >> operator overloading I see that different people may have
> >> different ideas about what it's meant to do...
> >
> > People complain too much about operator overloading sometimes ... but
> > here I have to admit I don't like it. If I see "is >> foo", I'm going
> > to assume it follows the standard pattern -- because a std::istream is
> > involved, not just because of the ">>".
> >
> Both of you make good points -- and I agree with you. The risk of name
> clash can be mitigated by putting the overloaded operator into a
> namespace. As for usefulness, the following code is quite descriptive
> for parsing a text file:

> string varName;
> int varValue;

> is >> varName >> ":=" >> varValue >> ";";

In this context it definitely looks much more "natural" than
in your original example, which made me a bit nervous;-) A
nice example that not just the "look" of the oberload itself
but also how it's used in its "natural habitat" can be quite
important in giving an impression of what it will do. I'd
probably still prefer to have a look at the definition, but
when I see it used like this I have some idea what to expect.

Jorgen Grahn

unread,
Feb 15, 2015, 2:44:54 AM2/15/15
to
On Sat, 2015-02-14, Norman J. Goldstein wrote:
> On 02/14/2015 03:02 PM, Jorgen Grahn wrote:
>> On Sat, 2015-02-14, Jens Thoms Toerring wrote:
>>> Norman J. Goldstein <nor...@telus.net> wrote:
>>>> operator>>( istream&,const char* ) succeeds if the extracted characters
>>>> exactly match the supplied const char*. Leading white space is ignored.
>>>> I find this a convenient way to help parse a file.
>>>
>>> Thank you for the clarification. It's the one hazards of
>>> operator overloading I see that different people may have
>>> different ideas about what it's meant to do...
>>
>> People complain too much about operator overloading sometimes ... but
>> here I have to admit I don't like it. If I see "is >> foo", I'm going
>> to assume it follows the standard pattern -- because a std::istream is
>> involved, not just because of the ">>".

> Both of you make good points -- and I agree with you. The risk of name
> clash can be mitigated by putting the overloaded operator into a
> namespace. As for usefulness, the following code is quite descriptive
> for parsing a text file:
>
> string varName;
> int varValue;
>
> is >> varName >> ":=" >> varValue >> ";";
>
> if( is.fail() ) { error }

I suspected your usecase was something like that, and yes,
it's neat.
0 new messages