这个 C++ 程序我做错了什么?

What am I doing wrong with this C++ program?

我正在尝试用 C++ 为我的计算机科学 class 创建一个咨询辅助程序,但不断收到错误:[错误] 'state' 没有命名类型和 [错误] 'state' 未在此范围内声明。有人可以让我知道我需要做什么才能获得这个程序 运行。我在出现错误的 C++ 文件下方包含了代码片段。我还提供了该程序运行所需的其他 C++ 文件的代码和资源文件。谢谢。

menu.cpp:

#include "menu.h"
#include "Course.h"
#include "Courses.h"

/// <summary>
/// Print menu options to stdout
/// </summary>
/// <param name=""></param>
void printMenu(void) {
    cout << "Menu:" << endl;
    cout << "  1. Load Data Structure." << endl;
    cout << "  2. Print Course List." << endl;
    cout << "  3. Print Course." << endl;
    cout << "  9. Exit" << endl << endl;
    cout << "What would you like to do? ";
}

/// <summary>
/// Call various functions based on the user's choice.
/// </summary>
/// <param name="choice"></param>
/// <param name="courses"></param>
void handleChoice(int choice, Courses& courses) {
    switch (choice) {
    case 1: // load file
        {
            string filename;
            auto state = cin.exceptions();  // setup exception handling for stdin
            cin.exceptions(std::istream::failbit | state);
            cout << "Please enter the name of the data file to load." << endl;
            cin.ignore();

            // if already loaded discard previous and start another 
            if (courses.getSize() > 0) {
                courses.clear();
            }

            try {
                getline(cin, filename);     // get user input of filename
                courses.loadFromCSV(filename);
            }
            catch (exception ex) {
                cout << ex.what() << endl;  // display what happened to console
            }

            cin.exceptions(state);          // restore previous exception settings
        }
        break;

    case 2: // print all courses with id and title in alphanumeric order
        cout << "Here is a sample schedule:" << endl << endl;
        courses.printAll();
        break;

    case 3: // print one course and its prerequisites
        {
            string courseId;
            cout << "What course do you want to know about? ";
            cin >> courseId;
            courses.printCourse(courseId);
        }
        break;

    case 9: // exit program
        cout << "Thank you for using the course planner!" << endl;
        break;

    default: // invalid choice
        cout << choice << "is not a valid option." << endl << endl;
        break;
    }
}

void commandLoop(void) {
    int choice = 0;
    Courses courses; // declaring here allocates the memory for the lifetime of the loop

    cout << "Welcome to the course planner." << endl;

    while (choice != 9) { // while not exit command
        cout << endl;
        printMenu();
        cin >> choice; // wait for user input
        handleChoice(choice, courses);
    }
}

main.cpp:

#include "menu.h"

int main(int argc, char* argv[]) {
    // calls the command loop with no command line arguments
    commandLoop();
}

Courses.cpp:

#include "Courses.h"

void Courses::addCourse(const Course course) {
    // if adding first element, push
    if (getSize() == 0) {
        append(course);
    } // if last element is less than one being inserted, push 
    // useful if file is mostly sorted
    else if (at(getSize() - 1).getId().compare(course.getId()) < 0) {
        append(course);
    }
    else { // otherwise insert which requires a binary search and then moving elements to make room
        size_t insertionPoint;
        insertionPoint = binarySearch(course.getId());

        if (insertionPoint != SIZE_MAX) {
            insert(insertionPoint, course);
        }
    }
}

size_t Courses::binarySearch(const string key) const {
    size_t midPoint = SIZE_MAX;
    size_t lowPoint = 0;
    size_t highPoint = getSize() - 1;

    // if the points haven't crossed each other continue
    // its possible for the highpoint to wrap around from zero to SIZE_MAX, stop when that happens
    while (highPoint != SIZE_MAX && highPoint >= lowPoint) { 
        midPoint = (highPoint + lowPoint) / 2; // locate the midpoint

        Course course = at(midPoint); // get value at midpoint

        if (course.getId() < key) {   // what we are looking for is in the lower half?
            lowPoint = midPoint + 1;
        }
        else if (course.getId() > key) { // what we are looking for is in the upper half?
            highPoint = midPoint - 1;
        }
        else {
            return midPoint;            // found a match
        }
    }

    // even if not found this is the closest point for insertion
    // caller is responsible for checking value to determine how used
    return midPoint; 
}

void Courses::printAll() const
{
    // already sorted so print out all courses by id and title
    for (size_t i = 0; i < getSize(); ++i) {
        Course course = at(i);
        cout << course.getId() << " " << course.getTitle() << endl;
    }
}

void Courses::printCourse(const string courseId) const {
    Course course = findCourse(courseId);

    if (course.getId().compare(courseId) == 0) {
        // found 
        course.print();
    }
    else {
        // not found
        cout << "Could not find course: " << courseId << endl;
    }
}

void Courses::loadFromCSV(const string filename, const string deliminator /* = "," */) {
    string line;            // holds a single line read from the file
    int lineNumber = 0;     // maintains a count of which line number in file we are on
    ifstream inputFile(filename.c_str()); // open input file

    if (inputFile.is_open())
    {
        while (inputFile.good())
        {
            // read line from file
            getline(inputFile, line);
            if (line != "") {
                ++lineNumber;
                auto tokens = splitString(line, deliminator); // split line into tokens by deliminator

                // check if there at least 2 tokens, id and title
                if (tokens.size() < 2) {
                    cout << "Error: Line format error, expected 2 or more tokens, got ";
                    cout << tokens.size() << " tokens, line number: " << lineNumber << endl;

                    // skip line we cannot parse
                    continue; // while (inputFile.good())
                }

                Course course;
                course.setId(tokens[0]);

                // check if course is already loaded
                Course duplicateCourse = findCourse(course.getId());
                if (duplicateCourse.getId() != "") {
                    cout << "Warning: Duplicate course detected, line number: ";
                    cout << lineNumber << endl;

                    // dont add duplicate
                    continue; // while (inputFile.good())
                }

                // we can parse and not a duplicate so set the rest of the properties
                course.setTitle(tokens[1]);

                // check for any prerequisites and add to course
                for (size_t i = 2; i < tokens.size(); ++i) {
                    string prerequisiteId = tokens.at(i);

                    // only add if prerequisite is already loaded
                    Course courseExists = findCourse(prerequisiteId);

                    if (courseExists.getId() == "")
                    {
                        cout << "Warning: Prerequisite not found, course: " << course.getId();
                        cout << ", prerequisite: " << prerequisiteId << endl;

                        // not found, skip to next
                        continue; // for (size_t i ...
                    }

                    // found, add course
                    course.addPrerequisite(courseExists);
                }

                // add course to data structure
                addCourse(course);
            }
        }
        inputFile.close();

        if (lineNumber == 0)
            throw runtime_error("No Data in " + filename);
    }
    else
        throw runtime_error("Failed to open " + filename);
}

Course Courses::findCourse(const string courseId) const {
    size_t index = binarySearch(courseId);
    if (index != SIZE_MAX) {
        Course course = at(index);

        if (course.getId().compare(courseId) == 0) {
            // found
            return course;
        }
        else {
            // not found
            return Course();
        }
    }
    else {
        // not found 
        return Course();
    }
}

vector<string> Courses::splitString(const string input, const string delimiter) const {
    string temp = input;
    size_t pos = 0;
    string token;
    vector<string> returnValue;

    while ((pos = temp.find(delimiter)) != std::string::npos) {
        token = temp.substr(0, pos);             // get token from input
        returnValue.push_back(token);            // add value to vector
        temp.erase(0, pos + delimiter.length()); // remove the part we found and leave the unfound for next call to find
    }

    if (temp.length() > 0) {
        returnValue.push_back(temp);            // add last value to vector
    }

    return returnValue;
}

Course.cpp:

#include "Course.h"

void Course::print() const {
    cout << id << ", " << title;

    // check if there are prerequisites to display
    if (prerequisites.size() > 0) {
        cout << endl << "Prerequisites: ";

        // display all
        for (size_t i = 0; i < prerequisites.size(); ++i) {
            cout << prerequisites.at(i).getId();

            // if before last, add delimiter
            if (i + 1 < prerequisites.size()) {
                cout << ", ";
            }
        }
    }

    cout << endl;
}

Course.h:

#ifndef __PROJECT_TWO_COURSE_H
#define __PROJECT_TWO_COURSE_H

#include <string>
#include <iostream>
#include <vector>

using namespace std;

class Course
{
private:
    string id;
    string title;
    vector<Course> prerequisites;

public:
    /// <summary>
    /// Default constructor
    /// </summary>
    Course() {
    }

    /// <summary>
    /// Accessor method for Id
    /// </summary>
    /// <returns></returns>
    string getId() const {
        return this->id;
    }

    /// <summary>
    /// Accessor method for Title
    /// </summary>
    /// <returns></returns>
    string getTitle() const {
        return this->title;
    }

    /// <summary>
    /// Mutator method for Id
    /// </summary>
    /// <param name="id"></param>
    void setId(const string id) {
        this->id = id;
    }

    /// <summary>
    /// Mutator method for Title
    /// </summary>
    /// <param name="title"></param>
    void setTitle(const string title) {
        this->title = title;
    }

    /// <summary>
    /// Add a prerequisite 
    /// </summary>
    /// <param name="course"></param>
    void addPrerequisite(const Course course) {
        prerequisites.push_back(course);
    }

    /// <summary>
    /// Display course Id, Title, and Prerequisites
    /// to stdout
    /// </summary>
    void print() const;
};

#endif

Courses.h:

#pragma once
#ifndef __PROJECT_TWO_COURSES_H
#define __PROJECT_TWO_COURSES_H

#include <stdexcept>
#include <vector>
#include <iostream>
#include <fstream>
#include <string>

    #include "Course.h"
    
    using namespace std;
    
    class Courses
    {
    private:
        /// <summary>
        /// Memory storage for the Course objects
        /// </summary>
        vector<Course> courses;
    
        /// <summary>
        /// High level, non-implementation specific method for adding a course
        /// to the underlying datatype.
        /// </summary>
        /// <param name="course"></param>
        void addCourse(const Course course);
    
        /// <summary>
        /// Called by addCourse
        /// Appends a course to the end of the data type
        /// Wraps the data type implementation
        /// Should call addCourse instead of this
        /// </summary>
        /// <param name="course"></param>
        void append(const Course course) {
            courses.push_back(course);
        }
    
        /// <summary>
        /// Called by addCourse
        /// Inserts a course somewhere into the data type
        /// Wraps the data type implementation
        /// Should call addCourse instead of this
        /// </summary>
        /// <param name="position">index of insertion</param>
        /// <param name="course">the course object to insert</param>
        void insert(const size_t position, const Course course) {
            vector<Course>::iterator iter;
            iter = courses.begin() + position;
            courses.insert(iter, course);
        }
    
        /// <summary>
        /// Wraps the data type at() call
        /// Use this instead of accessing the datatype directly
        /// </summary>
        /// <param name="index"></param>
        /// <returns></returns>
        Course at(const size_t index) const {
            return courses.at(index);
        }
    
        /// <summary>
        /// Performs a Binary Search of the data type
        /// The data type is expected to already be sorted
        /// Returns the midpoint regardless of found/not found
        /// in order to communicate the closest value
        /// The caller is responsible for checking the return value
        /// to determine a match or not. Caller should call getSize()
        /// before calling only call if > 0
        /// </summary>
        size_t binarySearch(const string key) const;
    
        /// <summary>
        /// Calls binarySearch and then checks the return value
        /// On match will return the course found
        /// On no match will return a default Course object
        /// </summary>
        Course findCourse(const string courseId) const;
    
        /// <summary>
        /// Splits a string into a vector<string> of tokens by a delimiter
        /// </summary>
        vector<string> splitString(const string input, const string delimiter) const;
    
    public:
        /// <summary>
        /// Clear all the data.
        /// </summary>
        void clear() {
            courses.clear();
        }
    
        /// <summary>
        /// Initialize the Courses object from a CSV file
        /// </summary>
        void loadFromCSV(const string filename, const string deliminator = ",");
    
        /// <summary>
        /// Print a specific course and its Prerequisites.
        /// </summary>
        void printCourse(const string courseId) const;
    
        /// <summary>
        /// Print all courses by Id and Title in alphanumeric order.
        /// </summary>
        void printAll() const;
    
        /// <summary>
        /// Wraps the data type size() call
        /// Use this instead of accessing the datatype directly
        /// </summary>
        /// <returns></returns>
        size_t getSize() const {
            return courses.size();
        }
    };
    
    #endif

ABCU 建议程序输入 (abcu.csv):

MATH201,Discrete Mathematics
CSCI300,Introduction to Algorithms,CSCI200,MATH201
CSCI350,Operating Systems,CSCI300
CSCI101,Introduction to Programming in C++,CSCI100
CSCI100,Introduction to Computer Science
CSCI301,Advanced Programming in C++,CSCI101
CSCI400,Large Software Development,CSCI301,CSCI350
CSCI200,Data Structures,CSCI101

如果代码

auto state = cin.exceptions(); 

给你错误

[Error] 'state' does not name a type

表示你在C++98模式下编译代码,其中auto还没有使用类型推导。那时,你可以auto int i = 0;来表示i是自动存储期限(反正没有auto)。

https://en.cppreference.com/w/cpp/keyword/auto

所以select至少C++11作为语言标准。