Error in Sutter book?

N

Noah Roberts

Item #1 in the More Exceptional C++ book uses the following construct:

fstream in;

....

process( in.is_open() ? in : cin,...);


Where process has been shown as having various multiple different
possible definitions. Among them is:

void process(basic_istream<char>& in,..);

I get errors when I try to do this in visual studio. It looked like an
erroneous construct to me to begin with (using ternary with two
different types being passed back) so I wanted to verify that it
actually worked and it doesn't. I also tried something like so:

istream & s = in.is_open() ? in : cin;

no go.

Working with pointers does work:

istream * s = in.is_open() ? &in : &cin;

This does not:

istream * s = &(in.is_open() ? in : cin);

Is the compiler breaking the standard here or is the use of the ternary
operator flawed?

Another definition he has is:

template < typename In, typename Out>
void process(In & in, Out & out)
{
....
}

But again, how can the ternary operator be used as such:

process(in.is_open() ? in : cin, ...)

I suppose the compiler could be really smart and derive a template
based on istream instead of either fstream or whatever cin is but I
don't think there is such a thing, is there? Or it could create two
instances of process and create a totally different branching
construct...again, I don't know of any that would and that seems on the
outside of qualifying for "as if".

But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.
 
N

Noah Roberts

Noah said:
istream & s = in.is_open() ? in : cin;

I suppose the error recieved might be of benefit. It is the same for
all uses (except the one pointer use that works) of the ternary
operator in my op.


1>c:\program files\microsoft visual studio 8\vc\include\istream(842) :
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access
private member declared in class 'std::basic_ios<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files\microsoft visual studio
8\vc\include\ios(151) : see declaration of
'std::basic_ios<_Elem,_Traits>::basic_ios'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function
'std::basic_istream<_Elem,_Traits>::basic_istream(const
std::basic_istream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
 
L

loufoque

Noah said:
Item #1 in the More Exceptional C++ book uses the following construct:

fstream in;

...

process( in.is_open() ? in : cin,...);


Where process has been shown as having various multiple different
possible definitions. Among them is:

void process(basic_istream<char>& in,..);

I get errors when I try to do this in visual studio.

Works fine for me with both GCC and Comeau.
 
A

Alf P. Steinbach

* Noah Roberts:
Item #1 in the More Exceptional C++ book uses the following construct:

fstream in;

...

process( in.is_open() ? in : cin,...);


Where process has been shown as having various multiple different
possible definitions. Among them is:

void process(basic_istream<char>& in,..);

I get errors when I try to do this in visual studio. It looked like an
erroneous construct to me to begin with (using ternary with two
different types being passed back) so I wanted to verify that it
actually worked and it doesn't. I also tried something like so:

istream & s = in.is_open() ? in : cin;

no go.

Working with pointers does work:

istream * s = in.is_open() ? &in : &cin;

This does not:

istream * s = &(in.is_open() ? in : cin);

Is the compiler breaking the standard here or is the use of the ternary
operator flawed?

Depends whether 'in' and 'cin' are of identical type. If they are, and
both are lvalues, the result is an lvalue. Otherwise the result is an
rvalue, which implies copying, which is meaningless for streams.


[snip]
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.

Check the errate pages. Perhaps there's something.
 
A

Alf P. Steinbach

* Noah Roberts:
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.

I was just skimming the 2nd edition of "The C++ Programming Language" by
Bjarne Stroustrup. Here 'main' is variously declared as

int main() {}
main() {}
void main() {}

Nobody's prefect.
 
N

Noah Roberts

Alf said:
* Noah Roberts:

Depends whether 'in' and 'cin' are of identical type. If they are, and
both are lvalues, the result is an lvalue. Otherwise the result is an
rvalue, which implies copying, which is meaningless for streams.

Since cin is set as an istream by the standard and in is an fstream
they are obviously not the same type even though they are related
types.
[snip]
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.

Check the errate pages. Perhaps there's something.

It isn't there.
 
N

Noah Roberts

Alf said:
* Noah Roberts:

I was just skimming the 2nd edition of "The C++ Programming Language" by
Bjarne Stroustrup. Here 'main' is variously declared as

int main() {}
main() {}
void main() {}

Nobody's prefect.

That's a rather minor error though. This one, if it is an error,
tosses out the entire advice given in that section. The first 5 pages
or so of the book become completely erroneous. This is why I'm trying
to figure out why I'm wrong and the book is right even though it
obviously doesn't compile on at least one pretty common compiler.
 
M

Michael

Item #1 in the More Exceptional C++ book uses the following construct:
fstream in;

...

process( in.is_open() ? in : cin,...);

Regrettably, I don't have a copy of this book, but could it be that it
declares the variable 'in' as an ifstream instead of an fstream? That
would seem to make sense in light of the downstream code
void process(basic_istream<char>& in,..);

Michael
 
D

Default User

Alf said:
* Noah Roberts:

I was just skimming the 2nd edition of "The C++ Programming Language"
by Bjarne Stroustrup. Here 'main' is variously declared as

int main() {}
main() {}
void main() {}

Nobody's prefect.

The second edition was pre-standard, I believe. The first two forms
were probably correct at the time, but I don't know about the third.
Consistency would probably have been better.




Brian
 
A

Alf P. Steinbach

* Noah Roberts:
Since cin is set as an istream by the standard and in is an fstream
they are obviously not the same type even though they are related
types.

The standard does not say anything about cin, only about std::cin.

[snip]
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.
Check the errate pages. Perhaps there's something.

It isn't there.

Too bad. Would you care to post a /complete/ code example? Then I (or
others) can say whether it's actually an error in the book (assuming
it's not an example of invalid code, discussed as such), or whether it's
a misinterpretation or something on your part.
 
B

bjarne

Indeed. However, that 2nd edition was published in 1991. It's a
venerable antique. Retire it to a top shelf somewhere and try again
with an up-to-date book, such as my 3rd edition - especially recent
printings; I maintain my books.

In 1991, seven years before we managed to ban "implicit int" in the
standard, plain

main() { }

was legal, as it had been since the first days of C.

"void main()" never was legal in C or C++. See :
http://www.research.att.com/~bs/bs_faq2.html#void-main

Assuming I wrote "void main", it was a bug. As somone said "nobody is
perfect". I had a quick look, but didn't find any occurrences of "void
main".

-- Bajrne Stroustrup; http://www.research.att.com/~bs
 
N

Noah Roberts

Alf said:
The standard does not say anything about cin, only about std::cin.

That's not being honest Alf. You know exactly to what I refer.
[snip]
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.
Check the errate pages. Perhaps there's something.

It isn't there.

Too bad. Would you care to post a /complete/ code example? Then I (or
others) can say whether it's actually an error in the book (assuming
it's not an example of invalid code, discussed as such), or whether it's
a misinterpretation or something on your part.

2. Write an ECHO program that simply echoes its input and that can be
invoked equivalently in the two following ways:

ECHO <infile >outfile
ECHO infile outfile

The Tersest Solution:


#include <iostream>
#include <fstream>

int main(int argc, char* argv[])
{
using namespace std;

(argc > 2
? ofstream(argv[2], ios::eek:ut | ios::binary)
: cout)
<<
(argc > 1
? ifstream(argv[1], ios::in | ios::binary)
: cin)
.rdbuf();
}


VC++ 8 output:


1>playground.cpp
1>c:\program files\microsoft visual studio 8\vc\include\ostream(581) :
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access
private member declared in class 'std::basic_ios<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files\microsoft visual studio
8\vc\include\ios(151) : see declaration of
'std::basic_ios<_Elem,_Traits>::basic_ios'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function
'std::basic_ostream<_Elem,_Traits>::basic_ostream(const
std::basic_ostream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1>c:\program files\microsoft visual studio 8\vc\include\istream(842) :
error C2248: 'std::basic_ios<_Elem,_Traits>::basic_ios' : cannot access
private member declared in class 'std::basic_ios<_Elem,_Traits>'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> c:\program files\microsoft visual studio
8\vc\include\ios(151) : see declaration of
'std::basic_ios<_Elem,_Traits>::basic_ios'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1> This diagnostic occurred in the compiler generated function
'std::basic_istream<_Elem,_Traits>::basic_istream(const
std::basic_istream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]
1>Project : warning PRJ0018 :
 
N

Noah Roberts

Michael said:
Regrettably, I don't have a copy of this book, but could it be that it
declares the variable 'in' as an ifstream instead of an fstream? That
would seem to make sense in light of the downstream code

No, it doesn't. In the terse example he does though and that also
doesn't work on this compiler.
 
O

Old Wolf

Noah said:
I also tried something like so:

fstream in;
istream & s = in.is_open() ? in : cin;

no go.

It works for me. The error message you posted, doesn't seem to
correspond to this construct. Can you post a complete program
that gives the error? (and the error itself that that program gives
you).

Also, try this:
istream & s = in.is_open() ? static_cast<istream &>(in) : cin;

Then the compiler will know to convert cin to istream& .
 
M

Mark P

Noah said:
Item #1 in the More Exceptional C++ book uses the following construct:

fstream in;

...

process( in.is_open() ? in : cin,...);


Where process has been shown as having various multiple different
possible definitions. Among them is:

void process(basic_istream<char>& in,..);

I get errors when I try to do this in visual studio. It looked like an
erroneous construct to me to begin with (using ternary with two
different types being passed back) so I wanted to verify that it
actually worked and it doesn't.

I've experienced similar compiler errors on other platforms. I don't
recall the exact details but it was something quite similar (write to
file or stdout, depending on something else). I believe g++ and Sun CC
accepted this, but HP's aCC compiler did not.
 
H

Herb Sutter

Noah Roberts said:
I get errors when I try to do this in visual studio. It looked like an
erroneous construct to me to begin with (using ternary with two
different types being passed back) so I wanted to verify that it
actually worked and it doesn't. I also tried something like so:

istream & s = in.is_open() ? in : cin;

no go.

Working with pointers does work:

istream * s = in.is_open() ? &in : &cin;

This does not:

istream * s = &(in.is_open() ? in : cin);

Is the compiler breaking the standard here or is the use of the ternary
operator flawed?

I'm not sure what it says in your printing, but IIRC in should have type
ifstream and out should have type ofstream. Then the code compiles fine
under most modern compilers (incl. EDG and gcc 3.x and 4.x).

It also worked fine under VC++ 6 (current when the book was published),
but oddly it apparently doesn't under VC++ 7.1 (2003) and 8.0 (2005). Hmm.
I'll look into it. In the meantime, a workaround would be to not use the
cuteness of the ternary operator, and work with a pointer instead:

ifstream in;
basic_istream<char>* i = &cin;

ofstream out;
basic_ostream<char>* o = &cout;

if( argc > 1 ) {
in.open ( argv[1], ios::in | ios::binary );
i = &in;
}

if( argc > 2 ) {
out.open( argv[2], ios::eek:ut | ios::binary );
o = &out;
}

Process( *i, *o );

Cheers,

Herb
 
A

Alf P. Steinbach

* Noah Roberts:
That's not being honest Alf. You know exactly to what I refer.

No, I don't have that book.

[snip]
But if I am right, how did this make it into such a high profile book
by such a high profile author...so I question my understanding.
Check the errate pages. Perhaps there's something.
It isn't there.
Too bad. Would you care to post a /complete/ code example? Then I (or
others) can say whether it's actually an error in the book (assuming
it's not an example of invalid code, discussed as such), or whether it's
a misinterpretation or something on your part.

2. Write an ECHO program that simply echoes its input and that can be
invoked equivalently in the two following ways:

ECHO <infile >outfile
ECHO infile outfile

The Tersest Solution:


#include <iostream>
#include <fstream>

int main(int argc, char* argv[])
{
using namespace std;

(argc > 2
? ofstream(argv[2], ios::eek:ut | ios::binary)
: cout)
<<
(argc > 1
? ifstream(argv[1], ios::in | ios::binary)
: cin)
.rdbuf();
}

Compilation fails with Comeau Online 4.3.8 and with MSVC 7.1, and as you
pointed out (snipped by me) with MSVC 8.0. It succeeds with g++ 3.4.4.

We're in §5.16/3, operands of different class types, call them E1 and
E2. Analysis of the first :? expression, with

E1 === std::eek:fstream( ... ) T1 === std::eek:fstream
E2 === std::cout T2 === std::eek:stream

where T1 is derived publicly from T2.

"If E2 is an lvalue", yes, then "E1 can be converted ..." to a direct
reference to T2, if that implicit conversion exists. It doesn't,
because E1 is an rvalue and std::eek:fstream naturally doesn't provide an
operator std::eek:stream&(). Next, there is a possible implicit conversion
to rvalue T2, which as I understand would involve copy construction, but
there is not or should not be any such accessible copy constructor in
std::eek:stream. Next, in para 5, if unsuccessful so far, the result is an
rvalue and overload resolution is applied to find a conversion, which
seems to be the same already tried above, but anyway, can't succeed for
the same reason: there's no applicable conversion function.

Next, the roles of E1 and E2 need to be switched and this new situation
analysed, but there's no way to convert std::eek:stream down to std::eek:fstream.

CC: Herb Sutter.
 
D

Daniel T.

Noah Roberts said:
1> This diagnostic occurred in the compiler generated function
'std::basic_istream<_Elem,_Traits>::basic_istream(const
std::basic_istream<_Elem,_Traits> &)'
1> with
1> [
1> _Elem=char,
1> _Traits=std::char_traits<char>
1> ]

There is your problem Noah. The code you are showing us is not the code
you get the error from. The above error is complaining about an attempt
to copy construct an istream, which of course can't be done.
 
A

Alf P. Steinbach

* bjarne:
Indeed. However, that 2nd edition was published in 1991. It's a
venerable antique. Retire it to a top shelf somewhere and try again
with an up-to-date book, such as my 3rd edition - especially recent
printings; I maintain my books.

I had the 3rd edition, but somebody got away with "borrowing" it and
never returning it. I don't know who that somebody was. However, I
also have the first edition, and that's very nice! :) Ach, old books.
I also have the first edition of K&R TCPPPL, and of "The Unix
Programming Environment" -- those were great days, with books written
for programmers rather than for modern students (dumbed down and
fattened up) or for language lawyers (almost artificially obfuscated),
and I really enjoyed and learned much from the first edition of TCPPPL.

In 1991, seven years before we managed to ban "implicit int" in the
standard, plain

main() { }

was legal, as it had been since the first days of C.

"void main()" never was legal in C or C++. See :
http://www.research.att.com/~bs/bs_faq2.html#void-main

Assuming I wrote "void main", it was a bug. As somone said "nobody is
perfect". I had a quick look, but didn't find any occurrences of "void
main".

First example I found now at the end of section 7.3.2, page 233. ;-)

Cheers,

- Alf
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top