本书未能编译,将ifstream转换为bool的示例

时间:2017-10-10 22:47:58

标签: c++ visual-studio-2017 intellisense

我是C ++的学生。我正在阅读“从C ++早期对象开始(第9版)”一书。第6章(关于函数)的示例27从文件中读取数据但不会编译。以下是完整代码:

// 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;
}

这是数据文件Rainfall.dat的随附数据:

Chicago 3.70
Tampa 6.49
Houston 3.80

问题出在“bool readData”函数中的这一行:

bool foundData = someFile >> city >> rain;

我正在使用2017年的Visual Studio社区。“someFile”获得一条红色波浪线,下拉列表显示以下错误:

  

std::basic_istream<char, std::char_traits<char>>”到“bool”之间没有合适的转化功能

我真的不明白错误信息,但设法让这个程序使用:

一个简单的演员:

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

或者作为替代方案:

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

所以,我真正的问题是:

  • 我的解决方案是否正常或是否有更好的方法?
  • 为什么教育材料上的错误被抛出 可以想象应该先进行彻底的测试。或者是这个 只是Visual Studio(intelliSense)特定,但工作得很好 其他编译器?

4 个答案:

答案 0 :(得分:8)

我会考虑

  • 返回std::ios&推迟上下文转换为bool

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

    结果是你可以像在路上一样简单地使用它:

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

    界面将只包含#include <iosfwd>

  • 进行编译
  • 手动触发上下文转换:

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

答案 1 :(得分:5)

该流有一个成员

explicit operator bool() const;

这使得它可以转换为bool值,但由于运算符为explicit,因此只能在需要 bool的上下文中使用。

您已经发现这包括if语句和显式强制转换。它不包括其他类型的表达式,如赋值。

最初(C ++ 98)运算符不是explicit(因为这些东西还没有发明)所以代码示例可能在当时有效。似乎该书尚未在本部分进行更新。

答案 2 :(得分:3)

流的operator bool以下列方式在基类basic_ios中声明

explicit operator bool() const;
^^^^^^^^

因此,没有从std::basic_ifstream到类型bool的隐式转换。

此解决方案

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

看起来不错。

您还可以通过以下方式使用逻辑否定运算符的技巧

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

因为根据C ++标准(5.3.1一元运算符)

  

9逻辑否定运算符的操作数!是上下文   转换为布尔(第4条);如果转换它的值是真的   操作数是假的,否则是假的。结果的类型是bool。

虽然在我看来第一个函数实现更具可读性。

答案 3 :(得分:2)

我认为他们不会在本书的后半部分介绍它,但我对此的处理方式有所不同。我首先要定义一个结构来保存一个城市的名称和降雨量:

struct precipitation { 
    std::string location;
    double amount;
};

然后我定义operator>>的重载以从流中提取该类型的对象:

std::istream &operator>>(std::istream &is, precipitation &p) { 
     return is >> p.location >> p.amount;
}

这几乎是流提取器的标准形式 - 引用流和对正在提取的类型的对象的引用,并返回流(再次,通过引用)。

这让你读得相当干净:

precipitation precip;

std::ifstream in("rainfall.dat");

while (in >> precip)
    std::cout << "City: " << precip.location << ", amount: " << precip.amount << "\n";

如果你想知道它是如何工作的:一个流对象支持转换为Boolean,当从流中读取成功时产生true,当它失败时产生false,所以这从流中读取直到读取失败,然后停止。

这也是流迭代器所期望的形式,因此它也允许您使用它们。例如,要将文件的全部内容读入矢量,您可以执行以下操作:

std::vector<precipitation> data { std::istream_iterator<precipitation>(in),{}};