33

A standard idiom is

while(std::getline(ifstream, str))
    ...

So if that works, why can't I say

bool getval(std::string &val)
{
    ...

    std::ifstream infile(filename);

    ...

    return std::getline(infile, val);
}

g++ says "cannot convert 'std::basic_istream<char>' to 'bool' in return".

Is the Boolean context of a return statement in a bool-valued function somehow different from the Boolean context of while(), such that the magic conversion that std::basic_istream performs in one context doesn't work in the other?


Addendum: There's apparently some version and perhaps language standard dependency here. I got the aforementioned error with g++ 8.3.0. But I don't get it with gcc 4.6.3, or LLVM (clang) 9.0.0.

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • hmm, works with a cast, but not implicitly - paging c++ level 5 wizards – pm100 Mar 14 '22 at 22:47
  • `return !!std::getline(infile, val);` would be an option – Ted Lyngmo Mar 14 '22 at 22:47
  • 3
    Precious few questions pique my interest as much as this one, good one. I look forward to seeing the answers since the compiler has all information needed to know it has to end up as a boolean. – paxdiablo Mar 14 '22 at 22:48
  • OT: @TedLyngmo Well, maybe it would be better something more "explicit": `return std::getline(infile, val).good();` – Bob__ Mar 16 '22 at 14:21

1 Answers1

49

The boolean conversion operator for std::basic_istream is explicit. This means that instances of the type will not implicitly become a bool but can be converted to one explicitly, for instance by typing bool(infile).

Explicit boolean conversion operators are considered for conditional statements, i.e. the expression parts of if, while etc. More info about contextual conversions here.

However, a return statement will not consider the explicit conversion operators or constructors. So you have to explicitly convert that to a boolean for a return.

Fatih BAKIR
  • 4,569
  • 1
  • 21
  • 27
  • 19
    so 'explicit' conversions sometimes arent – pm100 Mar 14 '22 at 22:51
  • 2
    Thank you. `explicit` is one of those diminishing-return nuances that my poor old brain doesn't consider important enough to learn, but slapping `bool(...)` around my `std::getline()` call seems to be working. – Steve Summit Mar 14 '22 at 22:53
  • 3
    'when initializing a new object of type T2, including return statement in a function returning T2;' - that's in the docs, why does it not apply here? – paxdiablo Mar 14 '22 at 22:54
  • @SteveSummit there's the old `!!` trick too. operand of `!` counts as "explicit" conversion to bool – M.M Mar 14 '22 at 22:54
  • @paxdiablo, that is only for implicit conversions. In C++ those will be constructors and operators not marked `explicit`. – Fatih BAKIR Mar 14 '22 at 22:55
  • 1
    @M.M Ted Lyngmo suggested that, too. That's probably what I would have tried next, without Fatih's answer. But the question here was "Why doesn't this work?", not "What can I use instead?". – Steve Summit Mar 14 '22 at 22:57
  • Sorry, damn ipad posted my comment early. The rest was that it also has 'when the expression is used in an if statement or a loop (T2 is bool).'. Surely that covers the while case? Or am I missing something? – paxdiablo Mar 14 '22 at 22:58
  • In other words, it looks like 'while' should also not consider explicit converters. ??? – paxdiablo Mar 14 '22 at 23:00
  • 2
    Never mind, just followed your link for the contextual conversions. The stuff I found seems to state where implicit conversion happens rather than where explicit conversions cannot. Your other link clarifies the distinction. Good answer. – paxdiablo Mar 14 '22 at 23:02
  • 6
    @M.M "*operand of ! counts as "explicit" conversion to bool*" - except in this case, since `istream` has an [`operator!`](https://en.cppreference.com/w/cpp/io/basic_ios/operator!) implemented. – Remy Lebeau Mar 14 '22 at 23:23
  • Instead of using the C-style cast `bool(...)` shouldn't we use `static_cast(...)` instead? – infinitezero Mar 16 '22 at 06:07
  • 1
    @infinitezero, `static_cast` debate aside, I think the C-style cast would be `(bool)...`, AFAIK `bool(...)` is C++-only. – Fatih BAKIR Mar 16 '22 at 06:40
  • Took me some searching but the `bool(...)` syntax is a form of https://en.cppreference.com/w/cpp/language/explicit_cast (point (2)): it translates directly to a C-style cast and is only usable for 1 word types. So, yeah for both those reasons I do think a static_cast seems more appropriate. – Emile Vrijdags Mar 16 '22 at 11:27