Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I create a template object based off of user input?

I have made an array based queue with a template so that the user can decide what kind of data is held inside the queue but I cannot figure out how gather input and then from that create a queue of that data type.

Here is my Queue

    #include <memory>
using namespace std;

template<class itemType>

class Queue
{
private:
   unique_ptr<itemType []> queueArray;
   int queueSize;
   int front;
   int rear;
   int numItems;
public:
   Queue(int);
   itemType peekFront();
   void enqueue(itemType item);
   void dequeue();
   bool isEmpty() const;
   bool isFull() const;
   void clear();
};

And I have tried this and many other ways but cant figure out how to tell what type of data the user inputs and then create a Queue with that type of data.

    int main()
{
    const int MAXSIZE = 5;
    int choice;

    cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
    choice = menu();

    if(choice == 1)
    {
        Queue<int> newQueue(MAXSIZE);
        int data;
    }
    else if(choice == 2)
    {
        Queue<string> newQueue(MAXSIZE);
        string data;    
    }
    else if(choice == 3)
    {
        Queue<float> newQueue(MAXSIZE);
        float data;     
    }
    else
        cout << "Number needs to be 1-3." << endl;

    cout << "Enter an item to add" << endl;
    cin >> data;

    newQueue->enqueue(data);

Thanks everyone for the help! I almost have it done, but now that I have all virtual functions how do I call peekFront()? Since the virtual functions can't return itemType right?

like image 597
Connor Corcoran Avatar asked Nov 19 '19 07:11

Connor Corcoran


2 Answers

You need runtime polymorphism to solve this problem. This can either be achieved with a base class:

class IQueue {
virtual ~IQueue() = default;
virtual void enqueue(istream&) = 0;
};

template<class itemType>
class Queue : public IQueue
{
//...
public:
    void enqueue(istream& is) override {
        itemType item;
        is >> item;
        enqueue(item);
    }
//...
};

And use as a pointer

int main() {
    //...
    unique_ptr<IQueue> newQueue;
    //...
    if(choice == 1)
    {
        newQueue.reset(new Queue<int>(MAXSIZE));
        int data;
    }
    //...
    newQueue->enqueue(cin);
    //...
}

Or something like std::variant.

like image 104
Teivaz Avatar answered Nov 10 '22 17:11

Teivaz


Well, you are almost there. You just need to not loose the scope of your data and newQueue variables.

template <typename T>
T input()
{
    T data;
    cout << "Enter an item to add" << endl;
    cin >> data;
    return data;
}
  int main()
{
    const int MAXSIZE = 5;
    int choice;

    cout << "1. integer queue\n" << "2. string queue\n" << "3. float queue\n";
    choice = menu();

    if(choice == 1)
    {
        Queue<int> newQueue(MAXSIZE);
        newQueue->enqueue(input<int>());    
    }
    else if(choice == 2)
    {
        Queue<string> newQueue(MAXSIZE);
        newQueue->enqueue(input<string>());     
    }
    else if(choice == 3)
    {
        Queue<float> newQueue(MAXSIZE);

        newQueue->enqueue(input<float>());    
    }
    else
        cout << "Number needs to be 1-3." << endl;


}

You still have some problem with this architecture, for example, maybe you want to move your queues outside these ifs, otherwise you can't use them anymore. (Read about scope).

You could also look at std::variant for these kind of situations.

like image 1
Federico Avatar answered Nov 10 '22 17:11

Federico