Home

Awesome

uberswitch

A header-only, unobtrusive, almighty alternative to the C++ switch statement that looks just like the original.

Sample usage (incomplete - see it working on godbolt: https://godbolt.org/z/WTx6K1)


// Enable nesting
#define UBERSWITCH_ALLOW_NESTING 1

// Include the tool 
#include <uberswitch/uberswitch.hpp>

// The holy grail of the switches: the string switch!
int string2num(std::string s) {
    uswitch (s) {
        ucase ("one"):
            return 1;

        ucase ("two"):
            return 2;

        ucase ("three"):
            return 3;

        // fallthrough works too
        ucase ("four"):
        ucase ("f0ur"):
            return 4;

        default: return -1;
    }
}
    
// More unexpected types work too
std::string pair2string(std::pair<int, int> p) {
    uswitch (p) {
        ucase (std::make_pair(1, 2)):
            return "12";

        // List initialization works too
        ucase ({3, 4}):
            return "34";

        default:
            return "Unknown pair";
    }
}

// You can actually switch over multiple items without packing them explicitly
// and the whole construct is constexpr!
constexpr const char* pair2string(int a, int b) {
    uswitch (a, b) {
        ucase (1, 2):
            return "12";

        ucase (3, 4):
            return "34";

        // And if you don't care about one of the items, you can use a wildcard
        ucase (uberswitch::any, 5):
            return "any5";
            
        // Fallthrough works as well.
        ucase (6, 7):
        ucase (8, 9):
            return "67 or 89";
            
        // And you can of course break out of the switch at any time.
        ucase (0, 0):
            break;
            
        default:
            return "Unknown (a,b)";
    }
    
    return "You found the code to break out!";
}

// Uberswitches can be nested if you define UBERSWITCH_ALLOW_NESTING to 1.
// In that case, fameta::counter will be used to get access to compile time scoped counters, which are needed for the nesting functionality.
constexpr const char* pair2string(int a, int b, int c) {
    uswitch (a, b) {
        ucase (1, 2):
            return "12";

        ucase (3, 4):
            return "34";

        default:
            // Starting a new uberswitch here!
            uswitch (a, c) {
                ucase (3, 5):
                    return "35";
                    
                // And you can of course also break out of a nested switch.
                ucase (0, 0):
                    break;

                default: 
                    return "Unknown (a,b)";
            }
            
            break;        
    }
    
    return "You found the code to break out!";
}

// Within the standard uberswitch the continue keyword acts just like the break keyword, which makes it unusable for its intended purpose.
// However, for those cases in which such a functionality is required, uberswitch_c and case_c can be used. 
// The trailing 'c' stands for 'context', which is an identifier or a number used as the first parameter of both and needs to be kept in synch between them. 
// Uberswitch_c and case_c cannot be used in constexpr functions and require c++17. This is a necessary cost to be able to use the continue keyword as it was intended.
std::string pairs_in_map(const std::map<int, std::string> &map) {
    std::string ret;
    
    for (const auto &p: map) {
        uswitch_c (M, p.first, p.second) {
            ucase_c (M, 1, "2"):
                ret.append("12");
                break;

            ucase_c (M, 3, "4"):
                ret.append("34");
                break;

            default:
                ret.append("[").append(std::to_string(p.first)).append(p.second).append("]");
                continue;
        }
        
        ret.append("-");
    }
        
    return ret;
}

// The above function, given the following map as input:
//
//     std::map<int, std::string> m {
//         { 2, "4"},
//         { 1, "2"},
//         { 5, "6"},
//         { 3, "4"},
//         { 7, "8"}
//    };
//
// Produces the following output:
//
//     12-[24]34-[56][78]