c++ use data in a vector as menu option

I have a .txt file that contains 3 lines:
1
2
3
Food
Drinks
Other


I read in that file:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
 ifstream inFile(menu.txt);
    
    if(!inFile)
    {
        cout << "Index File Not Found\n";
        inFile.close();
    }
    
    else
    {
        
        string line;
        
        //read in the relevant data
        while (std::getline(inFile, line))
        {
            
            menuVec.push_back(line);
           
        }
    }


and then I put the contents of that file into a menu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

do {
      cout << "Chose an option" << endl;
        
        for (int i = 0; i < menuVec.size(); i++) {
            cout << i+1 << ": " << menuVec[i] << endl;
        }
        
        cin >> option;
        
        if (option > menuVec.size())
        {
            do
            {
                cout << "Please input a valid option between 1 and " << menuVec.size() << endl;
                
                cin >> option;
                
            } while (option > menuVec.size());
        }
        
        if(option != 9)
        {
            //do something with user option
        }
   
   }while(option != 9)


So far everything works good and I have
1
2
3
1: Food
2: Drinks
3: Other


I was wondering is there a way to then get the user option and do something with it WITHOUT simply hard coding "if option 1, then... etc" because I want to make it so that there could be any possible number of options taken from that text file.

So I was thinking is there a way to turn that option into a string and then take the string (food, drink etc) into another class and work with it further. For example, open other text files with that name and giver yet another menu. So, if the useer choses #1, I then open a text file that has different foods and puts those in a menu etc etc.
Last edited on
First snippet: Lines 15: You're doing a getline to line.
Line 18: You're pushing tempString. tempString does not appear to have been defined. You want to be pushing line, not tempString.

I was wondering is there a way to then get the user option and do something with it WITHOUT simply hard coding

Unfortunately, there is no simple way to dynamically associate a text entry in your file with a specific section of code.

One approach is to put everything related to a menu selection in the file (food name, price, etc). Then your code to order a specific food becomes generic.

Another approach you might want to consider is create a std:map<string, funcptr>. You would initially load the map with the various names and function pointers to the code to handle that entry. Then when you read the file, you can check if the name is in the map. If so, you then have a pointer to the function to call when that menu item is selected.

open other text files with that name and giver yet another menu.

It's certainly possibly to open another file, but you still have the problem of associating an entry with code associated with those entries.


Last edited on
The map sounds good. How would I go about it? I've never used a map before...
Update: I now have a map that contains a string as a key and vector as the values:
map <string, vector<string>> restaurantMap

Here are the contents of the map:

Key: AB
Values: Burgers, Pizza, Icecream

Key: CB
Values: Pasta, Soup, Chocolate Cake


I wanted to make a menu option that kinda goes like this:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
do {
    cout << "Enter the name of the restaurant you would like to explore further, or E to exit: " << endl;
        
        for (int i = 0; i < resVec.size(); i++) {
            cout << i+1 << ": " << resVec[i] << endl;
        }
        
        cin >> option;

       for(int i = 0; i < resVec.size(); i++) {

              //find the key that corresponds with the user's input and if found, 
             //print out it's values as another menu option that they can use the same way as this one

            }
  } while (option != "e")


I need help finding the key that corresponds with the user's input
Last edited on
You can use the [] operator. In fact, the [] operator looks to see if the key exists, and if it does, it returns a reference to the value, so the 'find' part happens automatically.

So doing: restaurantMap[option] will allow you to access the value part of the map (i.e. the vector<string>) using the dot operator, or simply pass it to a function like below:

1
2
3
4
5
6
7
8
   cout << "Enter the name of the restaurant you would like to explore further, or E to exit: " << endl;
        
        for (int i = 0; i < resVec.size(); i++) {
            cout << i+1 << ": " << resVec[i] << endl;
        }
        
        cin >> option;
       printMenu( restaurantMap[option] ); // send vector to a function that prints it as menu 


Note, however, that if the user enters an option that does not exist as a key in the map, using the [] operator with that option will automatically create a new key-value pair element in the map, with that 'option' as the key and an empty vector. So perhaps you can check the size of the vector before sending it to the printMenu() function (i.e. make sure its not zero).
Last edited on
I know maps have a .find() function. Wouldn't it make more sense to use that? Although I'm not sure if the .find() can take the cin as a parameter though.
Last edited on
Yes, you can use the find member function, which returns an iterator to the key-value pair if found, or an iterator to map.end() otherwise. Thus, if the iterator returned is not equal to map.end(), simply call the printMenu() function with iterator->second
The map sounds good. How would I go about it?

Here's a pair of classes I use for implementing a dynamic menu.

menuitem.h
1
2
3
4
5
6
7
8
9
10
11
class MenuItem 
{   string      m_descr;
    void (* m_func) ();

public:
    MenuItem (const string & descr, void (*func)());
    
    void Execute ();
    
    friend ostream & operator << (ostream & os, const MenuItem & item);
};


menu.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class MENU
{   vector<MenuItem>    mv_menu;

    void Format (ostream & os) const;

public:
    MENU ();
    virtual ~MENU ();
    
    //  Accessors
    size_t size () const;
    
    void Add (CSTR_cref_t descr, void (*func)());
    void Execute (int testnum);
    
    friend ostream & operator << (ostream & os, const MENU & menu);
    
};

This dynamic menu is based on a vector rather than a map, but what I wanted to convey by posting this was associating a function pointer with a menu entry. The menu is built by calling menu::Add with a description and a pointer to a function that handles menu item when selected. menu::Add constructs a MenuItem and pushes it onto the vector. When map::Execute() is called with a test number, the MenuItem is located in the vector and the associated function is called through the saved function pointer.

This can easily be changed to use a map instead of a vector. In my case I wanted to use a numeric index, so a vector was well suited.

How do I use .find() on map <string, vector<string>> restaurantMap? Iterating through the vector is rather complicated...
Iterating through the vector is rather complicated...

Not really. Just use a for loop.
1
2
3
4
  for (int i=0; i<vec.size(); i++)
    if (vec[i].descr == descr)
    {  //  Match.  Do something
    }


How do I use .find() on map <string, vector<string>> restaurantMap?
1
2
3
4
5
6
7
8
9
   map <string, vector<string>>::iterator  iter;

    iter = restaurantMap.find (descr);
    if (iter == restaurantMap.end())
    {  // not found 
    }
    else
    {  // iter point to found entry 
    }




Okay, implemented it and it worked. Thanks!

Although I'm still lost on your dynamic menu classes. What exactly do they do?
MENU is a collection class (vector) of MenuItems.
Each MenuItem consists of a description and a pointer to a function that will be called when the menuitem is selected.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
  MENU mymenu; 

  void func_a ()
  {// Do something
  }

  void func_b ()
  { // Do something else
  }

  mymenu.Add ("Some description", func_a);  // Add a description that will call func_a()
  mymenu.Add ("Another decription", func_b); // Add another description that will call func_b()
  cout << mymenu << endl;  // Display the menu
  int choice;
  cout << "Enter choice: ";
  cin >> choice;
  mymenu->Execute (choice);  //  Call the function associated with the n'th MenuItem 


You can add as many menuitems as you wish and you can have multiple menus.

Last edited on
Topic archived. No new replies allowed.