5
\$\begingroup\$

Was thinking about extending the C switch beyond integers. Here is what it came to - will gladly accept any suggestions for improvement.Note: "Any class" in the title is not quite correct - the class should have equal operator and hash function to be used in this switch.

#include <iostream>#include <unordered_map>#include <string>#include <functional>template<typename T>using xmap = std::unordered_map<T, std::function<void()>>;template<typename T>void xwitch(const T& var, const xmap<T>& m, std::function<void()> otherwise = []() {}){    auto it = m.find(var);    if (it == m.end())        otherwise();    else        it->second();}#define SWITCH(var) xwitch(var, xmap<std::remove_const<decltype(str)>::type> {#define END_SWITCH });#define CASE {#define THEN , []() {#define END_CASE } },#define DEFAULT }, []() {int main(){    const std::string str{ "Second string" };    using namespace std::string_literals;    SWITCH(str)        CASE "First string"s THEN std::cout << "First string matched\n"; END_CASE        CASE "Second string"s THEN std::cout << "Second string matched\n"; END_CASE        CASE "Third string"s THEN std::cout << "Third string matched\n"; END_CASE    END_SWITCH        SWITCH("unmatched"s)        CASE "First string"s THEN std::cout << "First string matched\n"; END_CASE        CASE "Second string"s THEN std::cout << "Second string matched\n"; END_CASE        CASE "Third string"s THEN std::cout << "Third string matched\n"; END_CASE        DEFAULT std::cout << "No matches\n";    END_SWITCH}
askedJan 5, 2024 at 8:16
johngo's user avatar
\$\endgroup\$
2
  • \$\begingroup\$Technically this doesn't work on any class, since it requires the keys to implementoperator== andstd::hash<T>(...). But your question is valid regardless.\$\endgroup\$CommentedJan 5, 2024 at 17:13
  • 2
    \$\begingroup\$Why use macros?coliru.stacked-crooked.com/a/bdad77d62fe85c84\$\endgroup\$CommentedJan 5, 2024 at 17:45

1 Answer1

3
\$\begingroup\$

Design

I don't think I'd use these macros in production, but it seems like a useful tool for thinking about a proposal for how a more general C++switch might be implemented.

One improvement that could be made is to fall back tostd::map ifstd::unordered_map can't be used (for totally-ordered unhashable objects).

One disadvantage we have compared to a solution at language level is that the map is constructed dynamically each time theSWITCH() is reached, rather than requiring the map to beconstexpr and populating it during compilation. I don't see any easy way to rectify that. (I guess some users might consider this a feature, in that the cases can be computed at run-time, but I would prefer a visible map object for those.)

A serious weakness is that local variables aren't available to the code, because they are not captured in the lambdas. We might want to defineTHEN as, [&]{ to address that (I removed the unnecessary(), too).


Code

  • Missing include<type_traits>
  • InSWITCH() the typedecltype(str) ought to bedecltype(var).
  • <iostream> and<string> shouldn't be needed untilmain() - it's worth deferring them to show what's actually needed bySWITCH().
answeredJan 5, 2024 at 9:25
Toby Speight's user avatar
\$\endgroup\$
4
  • 1
    \$\begingroup\$He can work around the dynamic construction by storing the value in a local variable, then constructing the map asstatic, and then invoking it.coliru.stacked-crooked.com/a/30d3a96dda0fa53c\$\endgroup\$CommentedJan 5, 2024 at 17:55
  • \$\begingroup\$Thanks, Toby, I do think it'll be best as the language-level improvement. As for compile-time map, I tried making it a template class with operator (), but it was way more complicated.\$\endgroup\$CommentedJan 9, 2024 at 0:16
  • \$\begingroup\$Just checked - works fine without explicitly including type_traits. Well, at least in Visual Studio.\$\endgroup\$CommentedJan 9, 2024 at 0:24
  • \$\begingroup\$Relying on things working without including the documented headers is a big portability risk (even to future versions of the same compiler). I recommend including headers that the standard says you need, rather than playing fast and loose like that.\$\endgroup\$CommentedJan 11, 2024 at 8:26

You mustlog in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.