Как я могу разрешить пользователю определять тип шаблона?

#c #templates #if-statement #linked-list #switch-statement

#c #шаблоны #if-оператор #связанный список #оператор переключения

Вопрос:

Я написал рабочую связанную очередь, которая соответствует шаблону для своего типа данных, однако пользователь может вводить данные в одном из нескольких разных типов. Как я могу выбрать, какой тип данных будет использоваться во время выполнения?

Он отлично работает, если я использую каждый тип по отдельности; Мне просто нужно охватить все возможности без изменения кода или переписывания перегруженных функций для каждого типа данных.

Ниже я привел соответствующие фрагменты своего кода. Как я уже сказал, никаких проблем с функциями-членами моего класса нет.

Я уже пробовал оператор switch, который создает версию очереди типа x, но это не может работать, поскольку более поздние возможности в коммутаторе «противоречат» другим типам данных очереди. В настоящее время я пытаюсь использовать операторы if / else if без каких-либо ошибок, кроме тех, когда я пытаюсь использовать ввод типа x, он говорит, что он не определен.

 // From Source.cpp

#include <iostream>
#include <string>
using namespace std;
#include "LQueue.h"
int mainMenu();
int main()
{
    int value;
    bool stop = false;
    Queue<int> *theQueue;
    int choice = mainMenu();

    if (choice == 1) {
        Queue<int> theQueue;
        int dataType;
    }
    else if (choice == 2) {
        Queue<double> theQueue;
        double dataType;
    }
    else if (choice == 3) {
        Queue<string> theQueue;
        string dataType;
    }
    else if (choice == 4) {
        Queue<char> theQueue;
        char dataType;
    }

    cout << "nnHow many items would you like to initially"
        << " populate the queue with? ";
    int howMany;
    cin >> howMany;

    for (int i = 0; i < howMany; i  )
    {
        cin >> dataType;
        theQueue.enqueue(dataType)
    }

    theQueue.display(cout);

    theQueue.dequeue();

    theQueue.display(cout);

    return 0;
}
 
 int mainMenu()
{
    int choice;
    cout << "What type of data will you be storing in the queue?n"
        << "1. integersn2. decimal numbersn3. wordsn4. charsnn";

    cin >> choice;
    if (choice > 0 amp;amp; choice < 5)
        return choice;

    cout << "nnInvalid choicenn";
    mainMenu();
}
 
 // Guess I'll include shown functions from the Queue class file below

//--- Definition of enqueue()
template <typename QueueElement> 
void Queue<QueueElement>::enqueue(const QueueElement amp; value)
{
    if (empty())
    {
        myFront = myBack = new Node(value);
    }
    else
    {
        myBack->next = new Node(value);
        myBack = myBack->next;
    }
}

//--- Definition of dequeue()
template <typename QueueElement> 
void Queue<QueueElement>::dequeue()
{
    if (empty() == false)
    {
        Queue::NodePointer oldFront = myFront;
        myFront = myFront->next;
        delete oldFront;
    }
}

//--- Definition of display()
template <typename QueueElement> 
void Queue<QueueElement>::display(ostream amp; out) const
{
    Queue::NodePointer ptr;
    for (ptr = myFront; ptr != 0; ptr = ptr->next)
        out << ptr->data << "  ";
    out << endl;

}

//--- Definition of front()
template <typename QueueElement> 
QueueElement Queue<QueueElement>::front() const
{
    if (!empty())
        return (myFront->data);
    else
    {
        cerr << "*** Queue is empty "
            " -- returning garbage ***n";
        QueueElement * temp = new(QueueElement);
        QueueElement garbage = *temp;     // "Garbage" value
        delete temp;
        return garbage;
    }
}
 
 
Compiler (visual studio 2017) is showing identifier "dataType" is undefined within the following loop:
```c  

    for (int i = 0; i < howMany; i  )
        {
            cin >> dataType;
            theQueue.enqueue(dataType);
        }
 

2 ошибки: E0020 и C2065 в строке «cin>> Тип данных;», а также другая
C2065 в следующей строке

Может быть, есть более эффективный способ сделать это в целом? Я открыт для любых предложений, спасибо!

Комментарии:

1. обновление: я добавил typedef в начале основной функции.. и также изменил объявления переменных в if на typedefs… Сейчас работает, но я теряю данные после первого display(); вероятно, потому, что у меня нет нескольких определений для моего оператора присваивания. Для целых переменных работает просто отлично…. Уже спасибо тем, кто просмотрел lol xD

Ответ №1:

Проблема (проблема) заключается в том, что когда вы пишете

     if (choice == 1) {
        Queue<int> theQueue;
        int dataType;
    }
    else if (choice == 2) {
        Queue<double> theQueue;
        double dataType;
    }
    else if (choice == 3) {
        Queue<string> theQueue;
        string dataType;
    }
    else if (choice == 4) {
        Queue<char> theQueue;
        char dataType;
    }
 

вы определяете четыре разные theQueue и четыре разные dataType переменные, каждая из которых действительна только внутри соответствующего тела соответствующего if .

Итак, когда вы пишете

     for (int i = 0; i < howMany; i  )
    {
        cin >> dataType;
        theQueue.enqueue(dataType)
    }

    theQueue.display(cout);

    theQueue.dequeue();

    theQueue.display(cout);
 

больше нет dataType и theQueue доступны (все они находятся вне области видимости).

Я предлагаю что-то вроде следующего

     if (choice == 1) {
        foo<int>();
    }
    else if (choice == 2) {
        foo<double>();
    }
    else if (choice == 3) {
        foo<std::string>();
    }
    else if (choice == 4) {
        foo<char>();
    }
 

где foo() находится функция шаблона, похожая на эту (внимание: код не тестировался)

 template <typename T>
void foo ()
 {
   Queue<T> theQueue;
   T        dataType;

   std::cout << "nnHow many items would you like to initially"
        << " populate the queue with? ";
   int howMany;
   std::cin >> howMany;

   for (int i = 0; i < howMany; i  )
    {
      std::cin >> dataType;
      theQueue.enqueue(dataType)
    }

   theQueue.display(cout);

   theQueue.dequeue();

   theQueue.display(cout);
 }
 

Комментарии:

1. так следует ли определять foo() в файле заголовка, поскольку это шаблонная функция?

2. @K.Rile — Может быть. Или также в том же cpp-файле, где вызывается, если он вызывается только в этом cpp-файле.

3. Потрясающе! ваше предложение работает великолепно! Большое спасибо! 10/10 снова спросит, лол

4. Я предоставляю альтернативный метод, который ищет функцию по индексу

Ответ №2:

Напишите шаблонную функцию-член, которая выполняет то, что вы хотите:

 template<class DataType>
void processInput(int howMany) {
    DataType value;

    for (int i = 0; i < howMany; i  )
    {
        cin >> value;
        theQueue.enqueue(value);
    }

    theQueue.display(cout);

    theQueue.dequeue();

    theQueue.display(cout);
}
 

Метод 1 — оператор переключения

Затем мы можем использовать оператор switch для выбора между ними в main :

 int main()
{
    int choice = mainMenu();

    cout << "nnHow many items would you like to initially "
            "populate the queue with? ";
    int howMany;
    cin >> howMany;

    switch(choice) {
      case 1:
        processInput<int>(howMany);
        break;
      case 2:
        processInput<double>(howMany);
        break;
      case 3:
        processInput<string>(howMany);
        break;
      case 4:
        processInput<char>(howMany);
        break;
    }
}
 

Метод 2 — массив методов

Мы можем использовать массив для выполнения поиска!

 using func_t = void(*)(int);

int main() {

    std::vector<func_t> options = {
        processInput<int>, 
        processInput<double>, 
        processInput<string>, 
        processInput<char>
    };

    int choice = mainMenu();

    func_t selectedOption = options[choice - 1]; 

    cout << "nnHow many items would you like to initially "
            "populate the queue with? ";
    int howMany;
    cin >> howMany;

    selectedOption(howMany); 
}