3

I am working on my school project and was wondering If I could make my code look cleaner by replacing:

switch (screen) {
    case 0:
    switch (language) {
        case 0:
            std::cout << "1 - Start new game" << std::endl;
            std::cout << "2 - Load save" << std::endl;
            std::cout << "2 - Hall of fame" << std::endl;
            std::cout << "3 - Select language" << std::endl;
            std::cout << "h - Help" << std::endl;
            break;
        case 1:
            std::cout << "1 - Zacznij nową grę" << std::endl;
            std::cout << "2 - Wczytaj grę" << std::endl;
            std::cout << "2 - sala sławy" << std::endl;
            std::cout << "3 - wybierz język" << std::endl;
            std::cout << "h - pomoc" << std::endl;
            break;

    }
    break;
}

by something like this:

switch (screen)(language) {
    case 0 0:
            std::cout << "1 - Start new game" << std::endl;
            std::cout << "2 - Load save" << std::endl;
            std::cout << "2 - Hall of fame" << std::endl;
            std::cout << "3 - Select language" << std::endl;
            std::cout << "h - Help" << std::endl;
            break;
    case 0 1:
            std::cout << "1 - Zacznij nową grę" << std::endl;
            std::cout << "2 - Wczytaj grę" << std::endl;
            std::cout << "2 - sala sławy" << std::endl;
            std::cout << "3 - wybierz język" << std::endl;
            std::cout << "h - pomoc" << std::endl;
            break;

    }

Is there any construction like this in c++? I tried googling it, but no matter the phrasing I couldn't find anything.

  • 2
    No. Unless you want to use `if` statements with `&&`. If there's a range of allowed values, you could do some bit shifting though. Would make it harder to understand the code though. – ChrisMM May 19 '22 at 11:10
  • You could use `unordered_map,callback_t>` where `callback_t` could b e.g. `std::function` or something like that. – Quimby May 19 '22 at 11:15
  • For language-agnostic messages, I would recommend to store them in one big table per language and just index them with an `enum` e.g. `english_msgs[Msg::Main_menu]`. – Quimby May 19 '22 at 11:18
  • 1
    There are **proposals** for pattern matching in C++... if/when accepted, it would allow stuff like `inspect (screen, language) {when {0, 0}: /*..*/ when {1, 0} /*..*/}`. – Jarod42 May 19 '22 at 11:33

3 Answers3

3

I wouldn't recommend it for this sort of thing - there are better ways than using switch for localisation or for menus - and code should be doing one thing, but to combine two values into one you can use bitwise operations that shift by whole nibbles then hex literals in the cases:

switch ((screen << 4) | language) {
    case 0x00:
        std::cout << "1 - Start new game" << std::endl;
        std::cout << "2 - Load save" << std::endl;
        std::cout << "2 - Hall of fame" << std::endl;
        std::cout << "3 - Select language" << std::endl;
        std::cout << "h - Help" << std::endl;
        break;
    case 0x01:
        std::cout << "1 - Zacznij nową grę" << std::endl;
        std::cout << "2 - Wczytaj grę" << std::endl;
        std::cout << "2 - sala sławy" << std::endl;
        std::cout << "3 - wybierz język" << std::endl;
        std::cout << "h - pomoc" << std::endl;
        break;
    case 0x10:
        // screen 1 language 0
        break;
    case 0x11:
        // screen 1 language 1
        break;

    }
    break;
}

I wouldn't use this in an application, but have used it for lower level stuff, for example to combine the outputs of multiple rotary encoder sensor bits and previous states to determine direction of rotation.

Pete Kirkham
  • 48,893
  • 5
  • 92
  • 171
  • @Fareanor you need to shift by enough nibbles that all the bits you are putting the screen value into are blank and they won't interfere. If you have 255 languages then you shift by 8, and so on. – Pete Kirkham May 19 '22 at 11:35
  • @PeteKirkham Yes you're right, this is why I removed my comment ^^ – Fareanor May 19 '22 at 11:37
  • 1
    @Fareanor -- at the moment, the question was asked an hour ago. That's too soon to accept an answer. Accepting discourages others from answering, and might mean that the best possible answer never gets posted. – Pete Becker May 19 '22 at 12:50
3

As long as you can write a constexpr function from your inputs to an integral type, you can switch over multiple things.

constexpr int screen_and_language(int screen, int language) {
    return (screen << 4) | language;
}

switch screen_and_language(screen, language) {
    case screen_and_language(0, 0):
            std::cout << "1 - Start new game" << std::endl;
            std::cout << "2 - Load save" << std::endl;
            std::cout << "2 - Hall of fame" << std::endl;
            std::cout << "3 - Select language" << std::endl;
            std::cout << "h - Help" << std::endl;
            break;
    case screen_and_language(0, 1):
            std::cout << "1 - Zacznij nową grę" << std::endl;
            std::cout << "2 - Wczytaj grę" << std::endl;
            std::cout << "2 - sala sławy" << std::endl;
            std::cout << "3 - wybierz język" << std::endl;
            std::cout << "h - pomoc" << std::endl;
            break;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
2

Not directly but you can use a single variable that would hold all the semantic you need.

For example:

Value Meaning
0 screen==0 && language==0
1 screen==0 && language==1
2 screen==1 && language==0
3 screen==1 && language==1

Of course, you can use an enumeration instead so that it would be more explicit.

Which would then become:

enum MenuSettings {SL_00, SL_01, SL_10, SL_11};
Value Meaning
SL_00 screen==0 && language==0
SL_01 screen==0 && language==1
SL_10 screen==1 && language==0
SL_11 screen==1 && language==1

The downside with this workaround is that the enum would be pretty long if you have a lot of languages or/and a lot of screens to handle.

Fareanor
  • 5,900
  • 2
  • 11
  • 37