-2

While trying to filter the MainMenu array

const byte menuLength = 10;

struct Menu {
    int id;
    char Description[16];
    int parentId;
};

Menu MainMenu[menuLength] = {
    { 1, "SYSTEM SETUP   ", -1 },
    { 2, "FUNCTIONS SETUP", -1 },
    { 3, "FIRMWARE VER.  ", -1 },

    //SYSTEM SETUP
    { 4, "< BACK         ", 1 },
    { 5, "MODEL SELECT   ", 1 },
    { 6, "RX SETUP       ", 1 },

    //FUNCTIONS SETUP
    { 7, "< BACK         ", 2 },
    { 8, "REVERSE        ", 2 },
    { 9, "ENDPOINTS      ", 2 },
};

with this one

Menu GetSub(int parentId)
{
    int position = 0;
    Menu Filtered[menuLength];

    for (int i = 0; i < menuLength; i++)
    {
        if (parentId == MainMenu[i].parentId)
        {
            Filtered[position] = MainMenu[i];
            position++;
        }
    }
    return Filtered;
}

I get the following errors

  • 'Menu' does not name a type
  • could not convert '(Menu*)(& Filtered)' from 'Menu*' to 'Menu

So, how am i supposed to return the filtered array?

OrElse
  • 9,709
  • 39
  • 140
  • 253
  • 1
    [Can't reproduce](http://coliru.stacked-crooked.com/a/a9532c938a0a9fc1), the only error I get is about `return Filtered;`. We need a [mcve]. – HolyBlackCat May 07 '19 at 17:39
  • It would be extremely helpful, if i also knew, what is wrong with my question – OrElse May 07 '19 at 17:40
  • 2
    I didn't downvote, but I guess it's lack of a MCVE for a problem that we can't reproduce without one? – HolyBlackCat May 07 '19 at 17:41
  • @OrElse What they are looking for is the code you are compiling with filenames. So anybody can copy and paste it and then try and compile it. This also means removing all the stuff that is not relevant to the question so you have the minimum code in the question that reproduces your problem. – Martin York May 07 '19 at 17:42
  • 2
    What about using a `std::map` and using a `std::string` instead of a raw char array? – πάντα ῥεῖ May 07 '19 at 17:47
  • Unrelated, Why not three separate instances of `Menu`, one for each different menu? – user4581301 May 07 '19 at 17:52
  • 1
    Don't use C arrays. Use `std::array` for a fixed-length data and `std::vector` for variable length. And you life will get much simpler. – aparpara May 07 '19 at 17:57
  • @aparpara i will check this one – OrElse May 07 '19 at 18:00
  • Why do you need `id` field anyway. You can use array index as id and just pick references. Just make sure you checked -1 case and array index starts with 0 – Sugar May 07 '19 at 18:04

2 Answers2

6

First of all, please use C++ containers when you are using C++. Don't use variable sized arrays (VLA) and there are lots of articles why using it is bad. Use std::vector and std::string instead.

const byte menuLength = 10;

struct Menu {
    int id;
    std::string Description;
    int parentId;
};

std::vector<Menu> MainMenu = {
    { 1, "SYSTEM SETUP   ", -1 },
    { 2, "FUNCTIONS SETUP", -1 },
    { 3, "FIRMWARE VER.  ", -1 },

    //SYSTEM SETUP
    { 4, "< BACK         ", 1 },
    { 5, "MODEL SELECT   ", 1 },
    { 6, "RX SETUP       ", 1 },

    //FUNCTIONS SETUP
    { 7, "< BACK         ", 2 },
    { 8, "REVERSE        ", 2 },
    { 9, "ENDPOINTS      ", 2 },
};

std::copy_if

You can use std::copy_if to filter out the wanted menu.

std::vector<Menu> GetSub(const std::vector<Menu>& menu, int parentId)
{
  std::vector<Menu> sub;
  std::copy_if(menu.begin(), menu.end(), std::back_inserter(sub), [parentId](const Menu& m) {
    return m.parentId == parentId;
  });

  return sub;
}

LIVE DEMO

ranges::view::filter

With Eric Niebler's range-v3 library, this becomes even more trivial.

std::vector<Menu> GetSubRange(const std::vector<Menu>& menu, int parentId)
{
    return menu | ranges::view::filter([parentId](const Menu& m) { return m.parentId == parentId; })
}
TylerH
  • 20,799
  • 66
  • 75
  • 101
serkan.tuerker
  • 1,681
  • 10
  • 20
-3

You're trying to return an array of Menu objects via simply Menu object, you need to change function's prototype:

Menu GetSub(int parentId);

into

Menu * GetSub(itn parentId);

This function will return you a pointer to the array of Menu's, but then another problem will arise: you don't really know how many objects stored in an array. It can be solved by adding simple structure into your code:

struct MenuArray {
    Menu * ptr;
    int size;
}

And then remake your function like this:

MenuArray GetSub(int parentId)
{
    int position = 0;
    Menu * Filtered = new Menu[menuLength];

    for (int i = 0; i < menuLength; i++)
    {
        if (parentId == MainMenu[i].parentId)
        {
            Filtered[position] = MainMenu[i];
            position++;
        }
    }
    return MenuArray{Filtered, position};
}

We can also simply use STL vector, and that is the simplest solution if you can use it.

using std::vector;
vector<Menu> GetSub(int parentId)
{
    vector<Menu> Filtered(menuLength);

    for (int i = 0; i < menuLength; i++)
        if (parentId == MainMenu[i].parentId)
        {
            Filtered.push_back(MainMenu[i]);
        }

    return Filtered;
}
  • Yeah, it is, but actually managing with raw arras rather than vector actually includes some types of memory acquisition. – Александр Кушниренко May 07 '19 at 17:58
  • 2
    Some [RAII](https://stackoverflow.com/questions/2321511/what-is-meant-by-resource-acquisition-is-initialization-raii) and [Rule of Three](https://stackoverflow.com/questions/4172722/what-is-the-rule-of-three) action in `MenuArray` can make this safe and easy to use. Not all that certain that the Asker's not programming their way into unnecessary complexity, though. – user4581301 May 07 '19 at 18:00
  • 1
    Yeah, I understand, so std::vector will by the simplest solution in this case. – Александр Кушниренко May 07 '19 at 18:12
  • For what the Asker asked, yeah. Overall I think three separate menu arrays or `std::map`s and a state machine would be easier – user4581301 May 07 '19 at 18:31