我是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;
}
所以,我真正的问题是:
答案 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),{}};