Как перебрать вектор внутри структуры? - PullRequest
2 голосов
/ 28 сентября 2019

Я создаю своего рода цифровой торговый автомат для школы и столкнулся с проблемой.Я создал структуру Items для вендинга.Затем я создал структуру с именем Machine, которая содержит vector<Items>.Я хотел создать цикл for, который перебирает vector<Item> и отображает элементы, но я получаю следующую ошибку:

C:\Users\Nate\Desktop>g++ structversion.cpp -o structversion.exe -std=c++11
structversion.cpp: In function 'int test(Machine)':
structversion.cpp:29:20: error: 'begin' was not declared in this scope
   for (Item item : machine) {
                    ^
structversion.cpp:29:20: note: suggested alternatives:
In file included from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/string:51:0,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/locale_classes.h:40,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/ios_base.h:41,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/ios:42,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/ostream:38,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/iostream:39,
                 from structversion.cpp:1:
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/range_access.h:87:5: note:   'std::begin'
     begin(_Tp (&__arr)[_Nm])
     ^
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/range_access.h:87:5: note:   'std::begin'
structversion.cpp:29:20: error: 'end' was not declared in this scope
   for (Item item : machine) {
                    ^
structversion.cpp:29:20: note: suggested alternatives:
In file included from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/string:51:0,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/locale_classes.h:40,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/ios_base.h:41,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/ios:42,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/ostream:38,
                 from C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/iostream:39,
                 from structversion.cpp:1:
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/range_access.h:97:5: note:   'std::end'
     end(_Tp (&__arr)[_Nm])
     ^
C:/TDM-GCC-64/lib/gcc/x86_64-w64-mingw32/5.1.0/include/c++/bits/range_access.h:97:5: note:   'std::end'

Я прошу прощения, если это избыточный или тупой вопрос.Также здесь обсуждается код:

#include <iostream>
#include <vector>
#include <string>
using namespace std;

struct Item 
{
    string name;
    double price;
    unsigned int quantity;
    unsigned int amountInCart;
    bool addedToCart;
};

struct Machine { vector<Item> menu; };

void initItem(Item& i, string name, double price, unsigned int quantity,
    unsigned int amountInCart, bool addedToCart) 
{
    i.name = name;
    i.price = price;
    i.quantity = quantity;
    i.amountInCart = amountInCart;
    i.addedToCart = addedToCart;
}

test(Machine machine)
{
    for (Item i : machine) {
        cout << "item = " << i.name;
    }
}

main()
{
    Item cake;
    Item fruit;
    Item chips;
    Item soda;
    Item juice;

    initItem(cake, "Cake", 3.00, 5, 0, false);
    initItem(fruit, "Fruit", 4.20, 15, 0, false);
    initItem(chips, "Chips", 1.00, 6, 0, false);
    initItem(soda, "Soda", 1.50, 7, 0, false);
    initItem(juice, "Juice", 1.90, 10, 0, false);

    Machine machine;
    machine.menu.push_back(cake);
    machine.menu.push_back(fruit);
    machine.menu.push_back(chips);
    machine.menu.push_back(soda);
    machine.menu.push_back(juice);

    test(machine);
    return 0;
}

Функция test - это место, где я пытаюсь перебрать векторное меню в структуре Machine.

Я довольно новыйтак что, если у кого-то есть время и может ELI5, что я делаю неправильно, это было бы удивительно.

1 Ответ

4 голосов
/ 28 сентября 2019

Чтобы использовать цикл на основе диапазона для в ваших пользовательских типах, вам необходимо определить итераторы begin() и end().Это означает, что Machine должен иметь следующие функции-члены, которые возвращают итератор контейнера-члена. ( См. В режиме реального времени )

struct Machine
{
    vector<Item> menu;
    auto begin() { return menu.begin(); } // auto return requires C++14
    auto end()   { return menu.end();   }

    // or in C++11, you provide the correct return type
    // decltype(menu.begin()) begin() { return menu.begin(); }
    // decltype(menu.end())   end()   { return menu.end();   }
};

В противном случае вам необходимо предоставить итерационный объект непосредственно в цикл.Это означает, что в вашем случае для работы с минимальным изменением:

void test(Machine const& machine) // pass by `const-ref` as the machine is read-only inside the function
{
    for (const Item& i : machine.menu) { // const& : same reason as above ^^
    //                   ^^^^^^^^^^^^ --> std::vector has iterators: begin(), end() 
        cout << "item = " << i.name;
    }
}

Некоторые другие примечания:

  • Функция initItemне так, как обычно в C ++ (или любых других объектно-ориентированных языках программирования).Это работа конструктора .Чтобы изменить значение элемента (ов) в объекте, будет использоваться функция установки (члена).Хороший старт был бы:

    class Item
    {
    private:
        std::string name;
        double price;
        unsigned int quantity;
        unsigned int amountInCart;
        bool addedToCart;
    
    public:
        // constructor
        Item(std::string name, double price, unsigned int quantity,
            unsigned int amountInCart, bool addedToCart)
            : name{ name } // or name{ std::move(name) } when you learn about the move-semantics
            , price{ price}
            , quantity{ quantity }
            , amountInCart{ amountInCart }
            , addedToCart{ addedToCart }
        {}
        // ... getter and setter functions
    };
    

    Вы создаете объект сейчас как:

    Item cake{ "Cake", 3.00, 5, 0, false };
    
  • Пожалуйста, не практикуйте с using namespace std;.Смотрите здесь для более подробной информации: Почему «используется пространство имен std;»считается плохой практикой?
  • Я передал объект Machine в функцию test (также в цикле, основанном на диапазоне, Item объекты), переданную по квалифицированной ссылке const.Всякий раз, когда данные не могут быть изменены под любыми областями, вы должны передавать такие параметры, чтобы избежать нежелательного копирования ( creadits @ Klaus ):.Для дальнейшего чтения: Лучше ли в C ++ передавать по значению или передавать по константе?
...