书中的示例无法编译,将 ifstream 转换为 bool
Example from book failing to compile, converting ifstream into bool
我是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;
我正在使用 Visual Studio Community 2017。"someFile" 得到一条红色波浪线,下拉菜单显示以下错误:
no suitable conversion function from "std::basic_istream<char, std::char_traits<char>>
" to "bool
" exists
我不太理解错误消息,但已设法使该程序与以下项目一起工作:
一个简单的转换:
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;
}
所以,我真正的问题是:
- 我的解决方案可以吗还是有更好的方法?
- 为什么您在教育 material 上会抛出一个错误
可以想象应该首先进行彻底测试。或者是这个
只是 Visual Studio (intelliSense) 特定的,但在
其他编译器?
流有一个成员
explicit operator bool() const;
这使得它可以转换为 bool
值,但是因为运算符是 explicit
这只在 需要 布尔值的上下文中有效。
您已经发现这包括 if 语句和显式强制转换。它不包括其他类型的表达式,例如赋值。
最初 (C++98) 运算符不是 explicit
(因为还没有发明这样的东西)所以代码示例当时可能会起作用。这部分好像没更新。
流的 operator bool
在基 class 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 The operand of the logical negation operator ! is contextually
converted to bool (Clause 4); its value is true if the converted
operand is false and false otherwise. The type of the result is bool.
虽然在我看来第一个函数实现更具可读性。
我会考虑
返回 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};
}
我想他们直到本书的后面才会介绍它,但我会以不同的方式处理这个问题。我首先定义一个结构来保存城市的名称和降雨量:
struct precipitation {
std::string location;
double amount;
};
然后我将定义 operator>>
的重载以从流中提取该类型的对象:
std::istream &operator>>(std::istream &is, precipitation &p) {
return is >> p.location >> p.amount;
}
这几乎是流提取器的标准形式——引用一个流和一个被提取类型的对象的引用,return 流(再次通过引用)。
这可以让您阅读得相当清晰:
precipitation precip;
std::ifstream in("rainfall.dat");
while (in >> precip)
std::cout << "City: " << precip.location << ", amount: " << precip.amount << "\n";
如果您想知道它是如何工作的:流对象支持转换为布尔值,当从流中读取成功时生成 true
,失败时生成 false
,所以这从流中读取,直到读取失败,然后停止。
这也是流迭代器所期望的形式,因此您也可以使用它们。例如,要将文件的全部内容读入向量,您可以这样做:
std::vector<precipitation> data { std::istream_iterator<precipitation>(in),{}};
我是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;
我正在使用 Visual Studio Community 2017。"someFile" 得到一条红色波浪线,下拉菜单显示以下错误:
no suitable conversion function from "
std::basic_istream<char, std::char_traits<char>>
" to "bool
" exists
我不太理解错误消息,但已设法使该程序与以下项目一起工作:
一个简单的转换:
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;
}
所以,我真正的问题是:
- 我的解决方案可以吗还是有更好的方法?
- 为什么您在教育 material 上会抛出一个错误 可以想象应该首先进行彻底测试。或者是这个 只是 Visual Studio (intelliSense) 特定的,但在 其他编译器?
流有一个成员
explicit operator bool() const;
这使得它可以转换为 bool
值,但是因为运算符是 explicit
这只在 需要 布尔值的上下文中有效。
您已经发现这包括 if 语句和显式强制转换。它不包括其他类型的表达式,例如赋值。
最初 (C++98) 运算符不是 explicit
(因为还没有发明这样的东西)所以代码示例当时可能会起作用。这部分好像没更新。
流的 operator bool
在基 class 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 The operand of the logical negation operator ! is contextually converted to bool (Clause 4); its value is true if the converted operand is false and false otherwise. The type of the result is bool.
虽然在我看来第一个函数实现更具可读性。
我会考虑
返回
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}; }
我想他们直到本书的后面才会介绍它,但我会以不同的方式处理这个问题。我首先定义一个结构来保存城市的名称和降雨量:
struct precipitation {
std::string location;
double amount;
};
然后我将定义 operator>>
的重载以从流中提取该类型的对象:
std::istream &operator>>(std::istream &is, precipitation &p) {
return is >> p.location >> p.amount;
}
这几乎是流提取器的标准形式——引用一个流和一个被提取类型的对象的引用,return 流(再次通过引用)。
这可以让您阅读得相当清晰:
precipitation precip;
std::ifstream in("rainfall.dat");
while (in >> precip)
std::cout << "City: " << precip.location << ", amount: " << precip.amount << "\n";
如果您想知道它是如何工作的:流对象支持转换为布尔值,当从流中读取成功时生成 true
,失败时生成 false
,所以这从流中读取,直到读取失败,然后停止。
这也是流迭代器所期望的形式,因此您也可以使用它们。例如,要将文件的全部内容读入向量,您可以这样做:
std::vector<precipitation> data { std::istream_iterator<precipitation>(in),{}};