Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Example from book failing to compile, converting ifstream into bool

I am a student of C++. I am working through the book, "Starting Out With C++ Early Objects (9th Edition). Example 27 from Chapter 6 (on Functions) reads data from a file but will not compile. Here is the full code:

// Program 6-27
#include <iostream>
#include <string>
#include <fstream>
#include <iomanip>
using namespace std;

// Function prototype
bool readData(ifstream &someFile, string &city, double &rain);

int main()
{
    ifstream inputFile;
    string city;
    double inchesOfRain;

    // Display table headings
    cout << "July Rainfall Totals for Selected Cities \n\n";
    cout << " City      Inches \n";
    cout << "_________________ \n";

    // Open the data file
    inputFile.open("rainfall.dat");
    if (inputFile.fail())
    cout << "Error opening data file.\n";
    else
    {
        // Call the readData function
        // Execute the loop as long as it found and read data
        while (readData(inputFile, city, inchesOfRain) == true)
        {
            cout << setw(11) << left << city;
            cout << fixed << showpoint << setprecision(2)
                << inchesOfRain << endl;
        }
        inputFile.close();
    }
    return 0;
}

bool readData(ifstream &someFile, string &city, double &rain)
{
    bool foundData = someFile >> city >> rain;
    return foundData;
}

And here's the accompanying data for the data file Rainfall.dat:

Chicago 3.70
Tampa 6.49
Houston 3.80

The problem lies with this line in the "bool readData" function:

bool foundData = someFile >> city >> rain;

I am using Visual Studio Community 2017. "someFile" gets a red squiggly line and the dropdown displays the following error:

no suitable conversion function from "std::basic_istream<char, std::char_traits<char>>" to "bool" exists

I don't really understand the error message but have managed to get this program working with:

A simple cast:

bool readData(ifstream &someFile, string &city, double &rain)
{
    return static_cast<bool>(someFile >> city >> rain);
}

Or this as an alternative:

bool readData(ifstream &someFile, string &city, double &rain)
{
    if(someFile >> city >> rain)
        return true;
    else
        return false;
}

So, my real questions are:

  • Are my solutions ok or is there a better way?
  • why is an error being thrown at all on Educational material that you would imagine should have been thoroughly tested first. Or is this just Visual Studio (intelliSense) specific, but works just fine on other compilers?
like image 492
Webbmaster1 Avatar asked Oct 10 '17 22:10

Webbmaster1


2 Answers

The stream has a member

explicit operator bool() const;

which makes it convertible to a bool value, but because the operator is explicit this only works in a context that requires a bool.

You have already discovered that this includes if-statements and explicit casts. It doesn't include other types of expressions, like assignments.

Originally (C++98) the operator wasn't explicit (because such things weren't invented yet) so the code example would probably have worked at the time. Seems like the book hasn't been updated in this part.

like image 169
Bo Persson Avatar answered Sep 29 '22 20:09

Bo Persson


I'd consider

  • returning std::ios& to postpone the contextual conversion to bool

    std::ios& readData(std::ifstream &someFile, std::string &city, double &rain) {
        return someFile >> city >> rain;
    }
    

    The upshot is that you can simple use it like so down-the-road:

    if (readData(file, city, rain)) {
        // ...
    }
    

    The interface will compile with just including #include <iosfwd>


  • manually triggering the contextual conversion:

    bool readData(std::ifstream &someFile, std::string &city, double &rain) {
        return bool{someFile >> city >> rain};
    }
    
like image 38
sehe Avatar answered Sep 29 '22 20:09

sehe