Validating istream with std::ios_base::iostate

I have to write a stream extraction operator>> function which checks if the istream variable (stream) in the parameter is valid before returning it along with a delimiter (which is already provided).

I’m supposed to check that not only is stream valid (and there are no errors with it, such as it not being at the of the file, having permission, or having the right types), but I’m to do all that within a local object and later move it into place at the end if all goes well.

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

Here is a sample of the 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"

So my question is, would all this compile? Or perhaps is there a simple way of doing it?

4

Notes regarding the OP

So my question is, would all this compile? Or perhaps is there a simple way of doing it?

There are two questions here. The answers are: (1) Try it, and see. (2) Yes! See class Student below.

A problem with delimiter

When I plugged the code from the OP into a test framework I had created, initially, I got just a few errors. The first was a complaint about the C++23 character literal used to initialize variable delimiter. It is not yet supported by my compiler.

char delimiter = 'x{ 0000 }';  // A new kind of character literal from C++23

Since I was planning on changing this to a simple comma, anyway, I went ahead and did that.

char const delimiter = ',';
Unmatched parentheses

The next complaint was about a couple of unmatched parentheses, so I fixed that.

while (std::getline(stream, check) {         // <------ missing )
    if (!getline(iss, check, delimiter) {    // <------ missing )
        stream.setstate(std::ios::fail) abort();
    }
    //...
}
A bevy of errors

With those preliminaries out of the way, I was finally able to get the compiler to tell me what it really thinks, and the results were not good.

It gave me a bevy of errors, more than 130 lines worth, beginning with these.

1>C:UsersblotcOneDriveDocumentsProgrammingStackOverflowAnswersStackOverflow_78980542_ExtractGroceryItem_Question.cpp(57,47): error C3867: 'std::ios_base::fail': non-standard syntax; use '&' to create a pointer to member
1>C:UsersblotcOneDriveDocumentsProgrammingStackOverflowAnswersStackOverflow_78980542_ExtractGroceryItem_Question.cpp(57,53): error C2146: syntax error: missing ';' before identifier 'abort'
1>C:UsersblotcOneDriveDocumentsProgrammingStackOverflowAnswersStackOverflow_78980542_ExtractGroceryItem_Question.cpp(64,36): error C2440: '=': cannot convert from 'std::string' to 'double'
1>    C:UsersblotcOneDriveDocumentsProgrammingStackOverflowAnswersStackOverflow_78980542_ExtractGroceryItem_Question.cpp(64,36):

There was enough wrong that I decided it would better to demonstrate how to do it right, rather than to address each error, one-by-one.

A similar operator>>, for class Student

This appears to be some sort of homework assignment, so let’s go with a similar student/GPA example, instead grocery items.

In this example, and also in the OP, the sample data are structured into records.

  • Each record has 4 fields.
  • Fields are comma-separated, but there is no comma after the 4th field.
  • Whitespace can appear both before and after a delimiting comma.
  • The first 3 fields are quoted strings.
  • The 4th field is a floating-point number.
  • Any amount of whitespace can appear between records.

You can see the data I used for testing in function sample_data below. It includes one incomplete record at the end.

Function operator>> is a hidden friend

operator>> is defined within class Student, as a hidden friend. That way, it has access to the private data members of the class.

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::skipws
        >> 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;
}
Fail when a field cannot be extracted

The stream extraction is very similar to one of the operations from the OP. It chains together several extractions. If any one of them fails, stream will be placed into a failed state, and subsequent input operations will fail.

stream >> std::skipws
    >> std::quoted(local._studentID)
    >> a >> std::quoted(local._studentName)
    >> b >> std::quoted(local._major)
    >> c >> local._gpa;

The 4th field must be a well-formed, floating-point number. This helps to trap errors.

You can experiment below, by changing the sample data, to invalidate one or more of the fields.

  • If a number cannot be extracted from the 4th field, input fails.

  • If a string field contains embedded whitespace, and the quote mark is missing at its beginning, then the field will be interpreted to be two (or more) fields. This causes the data to become unsynchronized. Subsequent string extractions may appear to succeed, but when a string is encountered at what is supposed to be the 4th field, extraction will fail.

  • When the quote mark is missing at the end of a string, the following delimiter will be merged with the field. As before, this will cause the data to become unsynchronized, and extraction will fail when the 4th field turns out not to be a number.

Due to the way std::quoted works, if you remove both of the quote marks from a string field, extraction may succeed. This happens if the following conditions are true.

  • The field does not contain embedded whitespace, i.e., it is a “one-word” field.
  • The following delimiter is preceeded by whitespace, so that it will not be merged into the string.
Fail when the delimiter is invalid

Note that the delimiter is ',', rather than 'x{0000}'.

As delimiter characters are read in, each is stored in a separate character variable, a, b, or c. That makes it possible to verify that each one is a comma.

If any of them is not a comma, the following if-statement will place the stream into a failed state.

One thing worth pointing out: If the stream has already failed, it is not necessary to set its failbit a second time. We do it here, just to avoid a tangle of if-statements.

if (stream.fail() ||
    a != delimiter ||
    b != delimiter ||
    c != delimiter) {
    stream.setstate(std::ios_base::failbit);
}
Save and restore stream state

In operator>> (above), and also in operator<<, from the testing framework below, I/O manipulators are used to change the state of a stream.

  • Prior to input, std::skipws is “extracted” from the stream.
  • Prior to ouput, std::fixed and std::setprecision are “inserted” into the stream.

In production code, you might need to save the current settings of a stream, before they are modified by I/O manipulators such as the ones above. Then, after I/O is complete, you can restore the original stream settings.

For a homework assignment, such as this, that has been omitted.

Testing framework

Source code for the testing framework I used is given below.

Here are a few notes.

  • In the OP, operator>> contains a loop that inputs multiple records. That loop has been moved into function main below.

  • In the OP, operator>> contains what appears to be a check to see whether an input file was successfully opened. That check belongs in function main, as does the file-open operation itself.

  • The program below avoids using a file, by placing the sample data into a std::istringstream object, and reading from that.

// 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::skipws
            >> 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", "Beyonce"             , 
"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;
    while (iss >> student) {
        std::cout << student << 'n';
    }
    return 0;
}
// end file: main.cpp
Output
Student ID   : 00072250018548
Student name : Dwayne "The Rock" Johnson
Major        : Wrestling
GPA          : 2.8

Student ID   : 00028000517205
Student name : Beyonce
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

1

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật