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}- \$\begingroup\$Technically this doesn't work on any class, since it requires the keys to implement
operator==andstd::hash<T>(...). But your question is valid regardless.\$\endgroup\$Mooing Duck– Mooing Duck2024-01-05 17:13:17 +00:00CommentedJan 5, 2024 at 17:13 - 2\$\begingroup\$Why use macros?coliru.stacked-crooked.com/a/bdad77d62fe85c84\$\endgroup\$Mooing Duck– Mooing Duck2024-01-05 17:45:57 +00:00CommentedJan 5, 2024 at 17:45
1 Answer1
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> - In
SWITCH()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().
- 1\$\begingroup\$He can work around the dynamic construction by storing the value in a local variable, then constructing the map as
static, and then invoking it.coliru.stacked-crooked.com/a/30d3a96dda0fa53c\$\endgroup\$Mooing Duck– Mooing Duck2024-01-05 17:55:12 +00:00CommentedJan 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\$johngo– johngo2024-01-09 00:16:17 +00:00CommentedJan 9, 2024 at 0:16
- \$\begingroup\$Just checked - works fine without explicitly including type_traits. Well, at least in Visual Studio.\$\endgroup\$johngo– johngo2024-01-09 00:24:40 +00:00CommentedJan 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\$Toby Speight– Toby Speight2024-01-11 08:26:51 +00:00CommentedJan 11, 2024 at 8:26
You mustlog in to answer this question.
Explore related questions
See similar questions with these tags.
