我必须编写一个流提取
operator>>
函数,该函数检查参数中的istream变量(流)是否有效,然后将其与分隔符(已提供)一起返回。
我应该检查不仅流是否有效(并且没有错误,例如它不在文件的位置、具有权限或具有正确的类型),而且我要做所有的事情在本地对象内,如果一切顺利的话,最后将其移动到位。
std::istream& operator>>(std::istream& stream, GroceryItem& groceryItem) {
GroceryItem local; // local object
char delimiter = `\x{0000}`; // already provided
std::string check;
std::istringstream iss;
// implementing the rest of the code...
if (stream && stream.good()) {
// the if statement here checks if stream can be open and if there are
// no errors with it
while (std::getline(stream, check) {
if (!getline(iss, check, delimiter) {
stream.setstate(std::ios::fail) abort();
} else {
iss >> std::quoted(check, delimiter);
local._upcCode = check;
local._brandName = check;
local._productName = check;
local._price = check;
}
stream >> std::quoted(local._upcCode) >> delimiter
>> std::quoted(local._brandName) >> delimiter
>> std::quoted(local._productName) >> delimiter
>> local._price >> delimiter;
}
groceryItem = std::move(local)
} else {
return stream.setstate(std::ios::fail);
}
return stream;
}
这是流的示例
"00072250018548","Nature's Own","Nature's Own Butter Buns Hotdog - 8 Ct",10.79
"00028000517205", "Nestle" ,
"Nestle Media Crema Table Cream" ,
17.97
"00034000020706" ,
"York",
"York Peppermint Patties Dark Chocolate Covered Snack Size",
12.64 "00038000570742",
"Kellogg's", "Kellogg's Cereal Krave Chocolate",
18.66
"00014100072331" , "Pepperidge Farm", "Pepperidge Farm Classic Cookie Favorites", 14.43
"00000000000000", "incomplete / invalid item"
所以我的问题是,这一切都能编译吗?或者也许有一种简单的方法可以做到这一点?
所以我的问题是,这一切都能编译吗?或者也许有一个简单的方法可以做到这一点?
这里有两个问题。答案是:(1)尝试一下,然后看看。 (2)是的!请参阅下面的课程
Student
。
delimiter
当我将 OP 中的代码插入我创建的测试框架时,我得到的第一个错误是关于用于初始化变量
delimiter
的 C++23 字符文字的抱怨。我的编译器尚不支持它。
char delimiter = '\x{ 0000 }'; // already provided
因为我打算将其更改为简单的逗号,所以无论如何,我还是这么做了。
char const delimiter = ',';
下一个投诉是关于几个不匹配的括号,所以我解决了这个问题。
while (std::getline(stream, check) { // <------ missing )
if (!getline(iss, check, delimiter) { // <------ missing )
stream.setstate(std::ios::fail) abort();
}
//...
}
完成这些预备工作后,我终于能够让编译器告诉我它真正的想法,但结果并不好。
它给了我一系列错误,从这些开始。
1>C:\Users\blotc\OneDrive\Documents\Programming\StackOverflow\Answers\StackOverflow_78980542_ExtractGroceryItem_Question.cpp(57,47): error C3867: 'std::ios_base::fail': non-standard syntax; use '&' to create a pointer to member
1>C:\Users\blotc\OneDrive\Documents\Programming\StackOverflow\Answers\StackOverflow_78980542_ExtractGroceryItem_Question.cpp(57,53): error C2146: syntax error: missing ';' before identifier 'abort'
1>C:\Users\blotc\OneDrive\Documents\Programming\StackOverflow\Answers\StackOverflow_78980542_ExtractGroceryItem_Question.cpp(64,36): error C2440: '=': cannot convert from 'std::string' to 'double'
1> C:\Users\blotc\OneDrive\Documents\Programming\StackOverflow\Answers\StackOverflow_78980542_ExtractGroceryItem_Question.cpp(64,36):
错误已经够多了,因此我决定最好演示如何正确执行,而不是逐一解决每个错误。
operator>>
,用于班级Student
这似乎是某种家庭作业,所以让我们以类似的学生/GPA 为例,而不是杂货。
在此示例中,也在 OP 中,示例数据被结构化为 records。
operator>>
operator>>
在类Student
中定义,作为隐藏的朋友。这样,它就可以访问类的私有数据成员。
friend std::istream& operator>>(std::istream& stream, Student& student)
{
Student local;
char const delimiter{ ',' }; // Use comma, NOT '\x{0000}'
char a, b, c;
stream >> std::quoted(local._studentID)
>> a >> std::quoted(local._studentName)
>> b >> std::quoted(local._major)
>> c >> local._gpa;
if (stream.fail() ||
a != delimiter ||
b != delimiter ||
c != delimiter) {
stream.setstate(std::ios_base::failbit);
}
else {
student = std::move(local);
}
return stream;
}
流提取与 OP 中的操作之一非常相似。它将多个输入操作链接在一起。如果其中任何一个失败,
stream
将被置于失败状态,并且随后的 I/O 将失败。
stream >> std::quoted(local._studentID)
>> a >> std::quoted(local._studentName)
>> b >> std::quoted(local._major)
>> c >> local._gpa;
delimiter
请注意,分隔符是
','
,而不是 'x{0000}'
。
读入分隔符时,每个分隔符都存储在单独的字符变量
a
、b
或 c
中。这样就可以验证每个都是逗号。
如果其中任何一个不是逗号,则以下 if 语句会将流置于失败状态。
值得指出的一件事:如果流已经失败,则无需再次设置其
failbit
。我们在这里这样做,只是为了避免 if 语句的混乱。
if (stream.fail() ||
a != delimiter ||
b != delimiter ||
c != delimiter) {
stream.setstate(std::ios_base::failbit);
}
这是我用于测试的框架。
在OP中,
operator>>
包含一个输入多个记录的循环。该循环已移至下面的函数 main
中。
在OP中,
operator>>
包含似乎是检查输入文件是否已成功打开的内容。该检查属于函数 main
,文件打开操作本身也是如此。
下面的程序通过将示例数据放入
std::istringstream
对象并从中读取来避免使用文件。
// main.cpp
#include <iomanip> // quoted, setprecision
#include <iostream> // cout, fixed, ios_base, istream, ostream
#include <sstream> // istringstream
#include <string> // getline, string
#include <utility> // move
//======================================================================
// Student
//======================================================================
class Student
{
std::string _studentID;
std::string _studentName;
std::string _major;
double _gpa{};
public:
Student()
= default;
Student(
std::string studentID,
std::string studentName,
std::string major,
double gpa)
: _studentID{ studentID }
, _studentName{ studentName }
, _major{ major }
, _gpa{ gpa }
{}
// More member functions
// ...
friend std::ostream& operator<<(std::ostream& stream, Student const& student)
{
stream << std::fixed << std::setprecision(1)
<< "Student ID : " << student._studentID
<< "\nStudent name : " << student._studentName
<< "\nMajor : " << student._major
<< "\nGPA : " << student._gpa
<< '\n';
return stream;
}
friend std::istream& operator>>(std::istream& stream, Student& student)
{
Student local;
char const delimiter{ ',' }; // Use comma, NOT '\x{0000}'
char a, b, c;
stream >> std::quoted(local._studentID)
>> a >> std::quoted(local._studentName)
>> b >> std::quoted(local._major)
>> c >> local._gpa;
if (stream.fail() ||
a != delimiter ||
b != delimiter ||
c != delimiter) {
stream.setstate(std::ios_base::failbit);
}
else {
student = std::move(local);
}
return stream;
}
};
//======================================================================
// sample_data
//======================================================================
std::string sample_data() {
return
R"sample("00072250018548","Dwayne “The Rock” Johnson","Wrestling",2.8
"00028000517205", "Beyoncé" ,
"Music" ,
4.0
"00034000020706" ,
"Cristiano Ronaldo",
"Futebol",
4.0 "00038000570742",
"Kim Kardashian", "Undeclared",
1.9
"00014100072331" , "Oprah Winfrey", "Broadcast Journalism", 3.2
"00000000000000", "incomplete / invalid item"
)sample";
}
//======================================================================
// main
//======================================================================
int main()
{
std::istringstream iss{ sample_data() };
Student student;
int count{};
while (iss >> student) {
std::cout << student << '\n';
}
return 0;
}
// end file: main.cpp
Student ID : 00072250018548
Student name : Dwayne ôThe Rockö Johnson
Major : Wrestling
GPA : 2.8
Student ID : 00028000517205
Student name : BeyoncΘ
Major : Music
GPA : 4.0
Student ID : 00034000020706
Student name : Cristiano Ronaldo
Major : Futebol
GPA : 4.0
Student ID : 00038000570742
Student name : Kim Kardashian
Major : Undeclared
GPA : 1.9
Student ID : 00014100072331
Student name : Oprah Winfrey
Major : Broadcast Journalism
GPA : 3.2