9

The canonical way to read lines from a text file is:

std::fstream fs("/tmp/myfile.txt");
std::string line;
while (std::getline(line, fs)) {
   doThingsWith(line);
}

(no, it is not while (!fs.eof()) { getline(line, fs); doThingsWith(line); }!)

This works beacuse std::getline returns the stream argument by reference, and because:

  • in C++03, streams convert to void*, via an operator void*() const in std::basic_ios, evaluating to the null pointer value when the fail error flag is set;
    • see [C++03: 27.4.4] & [C++03: 27.4.4.3/1]
  • in C++11, streams convert to bool, via an explicit operator bool() const in std::basic_ios, evaluating to false when the fail error flag is set
    • see [C++11: 27.5.5.1] & [C++11: 27.5.5.4/1]

In C++03 this mechanism means the following is possible:

std::cout << std::cout;

It correctly results in some arbitrary pointer value being output to the standard out stream.

However, despite operator void*() const having been removed in C++11, this also compiles and runs for me in GCC 4.7.0 in C++11 mode.

How is this still possible in C++11? Is there some other mechanism at work that I'm unaware of? Or is it simply an implementation "oddity"?

Community
  • 1
  • 1
Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • eek another reason not to like the iostreams part of STL – Doug T. Feb 02 '13 at 03:30
  • @DougT.: Yeah or the C++ Standard Library. – Lightness Races in Orbit Feb 02 '13 at 03:31
  • The question of why something is this way or that way in a language make for the worst threads on SO. Very few people, if any, will know why. Bad question. – Nocturno Feb 02 '13 at 04:00
  • 3
    @Nocturno, It's not a question of why as in why `bool` instead of `void *` (or equivalent). It's a question of why, as far as the OP knows, C++11 says that the code shouldn't output an address, but it does. Please correct me if I misinterpreted. – chris Feb 02 '13 at 04:03
  • 3
    @Nocturno: I think you misunderstood the question. It's not a request for a rationalisation. I wanted someone to tell me which C++11 language feature enabled `std::cout << std::cout` to remain valid despite the removal of `operator void*() const`. – Lightness Races in Orbit Feb 02 '13 at 04:03
  • 3
    Also, "very few people, if any, will know why" is _never_ a reason for a "bad question". It just means that there will be only one or two answers instead of .. oh, wait a minute! If anything, it makes for a _good_ question by spreading that knowledge around. – Lightness Races in Orbit Feb 02 '13 at 04:03
  • @Nocturno: I've changed the wording slightly for your benefit. The question hasn't changed. – Lightness Races in Orbit Feb 02 '13 at 04:05
  • 1
    +1 Really good question + answer. This is a really good thread. – Mark Garcia Feb 02 '13 at 04:14
  • I just don't understand how someone could not have the heart to explain why they think this question/answer is bad. It really is hard to improve when you have no idea what someone's problem with it is. – chris Feb 02 '13 at 04:18
  • @chris: Yeah, it's really hard to improve the downvoting-skills of SO users who are getting it wrong, when they won't explain _how_ they got it wrong! – Lightness Races in Orbit Feb 02 '13 at 04:19
  • 3
    @DougT. *"another reason not to like the iostreams part of STL"* - Since iostreams aren't part of the STL, there isn't much to like or not like. (sorry for the nitpicking but I hope it's in the spirit of the OP) ;) – Christian Rau Feb 02 '13 at 13:56
  • @LightnessRacesinOrbit I've been waiting for an example to present itself, and here it is [Why does C not define minimum size for an array?](http://stackoverflow.com/questions/14695254/why-does-c-not-define-minimum-size-for-an-array). That question is similar in spirit to your question here, and was closed today. My opinion is that you will never get a definitive answer from questions like these, unless the makers of that language turn up to answer it. That's what I meant by very few people if any will have the right answer. You just wind up with a whole lot of speculation. – Nocturno Feb 04 '13 at 23:01
  • @Nocturno: There are plenty of people on SO who have contributed to the language and are either on or close to those who are on the committee. Myself I am personally familiar with at least two people on the committee, and we converse both on IRC and on SO fairly regularly. So it's far from impossible to get their input here. – Lightness Races in Orbit Feb 05 '13 at 01:42
  • 1
    @Nocturno: Anyway, this question is _not_ that kind of question. I am not asking for any rationale for feature development. It's a question about what _is_ already there in the standard, regardless of how that came about originally. So I still think you're misunderstanding it at a fundamental level. The answers all _grok_ that, and my acceptance of one should help clarify the intent of the question. – Lightness Races in Orbit Feb 05 '13 at 01:43

3 Answers3

6

As late as GCC 4.6.2, the libstdc++ code for basic_ios is evidently still C++03-like.

I'd simply put this down to "they haven't gotten around to it yet".

By contrast, the libc++ (LLVM's stdlib implementation) trunk already uses operator bool().

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • Yup, the `ostream` (or maybe just `fstream`) classes also don't have move or swap yet either. – GManNickG Feb 02 '13 at 03:34
  • Worth noting that I found the same thing in MSVC 11's `xiosbase`. – chris Feb 02 '13 at 03:35
  • 3
    It may also be an "implementation-specific non-portable extension" included for backward compatibility purposes. – Ben Voigt Feb 02 '13 at 03:49
  • I just scanned the stdlib headers of G++ 4.7 and I found out that `basic_ostream` implements `operator bool`, while its super-class `basic_ios` implements `operator void*`. So `ostream` should have both operators, right? – leemes Feb 02 '13 at 03:49
  • Oh, nevermind, that `operator bool` is in the `basic_ostream<...>::sentry` nested class. So you're absolutely right: `basic_ostream` only implements `operator void*`. – leemes Feb 02 '13 at 03:51
  • 4
    And a downvote on this, too! What's going on? What's wrong with this answer, pray tell? I know that it answers the question, because I wrote the question. – Lightness Races in Orbit Feb 02 '13 at 04:05
  • 1
    Probably just people against self-answers, even though they're perfectly acceptable. Oh well! – GManNickG Feb 02 '13 at 04:24
  • The "unspecified-bool-type" comes from paranoia; when you have a conversion to `void*` it's possible for someone to `delete my_stream`, so some folks invented "unspecified-bool-type" which is typically a pointer to member function. But when the standard requires `operator void*()`, "unspecified-bool-type" is not a suitable replacement. – Pete Becker Feb 02 '13 at 13:15
  • 1
    @PeteBecker, It was discovered (and you can see for yourself in the link) that the unspecified-bool-type was in a giant comment. The `operator bool()` is later. – chris Feb 03 '13 at 14:59
  • 3
    Well, I'll try to get around to it. ;) It won't make it for 4.8 because that's about to branch. I suspect there are a lot of missing bits in pre-2011 old headers. We were all hell bent on adding the big new stuff. – emsr Feb 03 '13 at 15:28
6

I'm reasonably certain this is not allowed/can't happen in a conforming implementation of C++11.

The problem, of course, is that right now, most implementations are working on conforming, but aren't there completely yet. At a guess, for many vendors, this particular update is a fairly low priority. It improves error checking, but does little (or nothing) to enable new techniques, add new features, improve run-time efficiency, etc. This lets the compiler catch the error you've cited (some_stream << some_other_stream) but doesn't really make a whole lot of difference otherwise.

If I were in charge of updating a standard library for C++11, I think this would be a fairly low priority. There are other changes that are probably as easy (if not easier) to incorporate, and likely to make a much bigger difference to most programmers.

To use one of the examples you gave, if I were in charge of updating the VC++ standard library to take advantage of the compiler features added in the November CTP, my top priority would probably be to add constructors to the standard container types to accept initialization_lists. These are fairly easy to add (I'd guess one person could probably add and test them in under a week) and make quite an obvious, visible difference in what a programmer can do.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 1
    While your reasoning is completely undrstandable, removing this `operator void*` (or turning it into an `explicit operator bool`) is a mere no-op and leagues faster and easier than e.g. implementing proper `initializer_list` constructors. Still the most probable explanation +1. – Christian Rau Feb 02 '13 at 14:00
  • 2
    +1 : libc++ gives: error: invalid operands to binary expression. – Howard Hinnant Feb 03 '13 at 19:50
2

This was a missed mini-feature buried in a pre-existing header. There are probably lots of missing error of omission and commission in pre-2011 components.

Really, if anyone comes up with things like this in gcc then it would do a world of good to go to Bugzilla and make a bug report. It may be a low priority bug but if you start a paper trail

I'll go out on a limb and extend this idea to all the other C++ compilers: clang, Visual Studio,etc.

This will make C++ a better place.

P.S. I entered a bug in Bugzilla.

emsr
  • 15,539
  • 6
  • 49
  • 62