#include <boost/typeof/typeof.hpp> #include <cassert> /* Store a value of type V */ template<typename V> struct S { operator int() { return -1; } S(V const& data):data(data), matched(false) { } V data; bool matched; }; #define sswitch(V) \ switch(S<BOOST_TYPEOF(V)> _s_ = V) \ case -1: { if(0) #define scase(V) \ } if(!(_s_.matched || _s_.data == V)) ; else \ if(!(_s_.matched = true)) ; else { case __LINE__ #define sdefault() \ } default #define snodefault(MSG) \ } do { assert(!MSG); __builtin_unreachable(); } while(0)That looks pretty weird! What are its drawbacks?
- A default case must always be present and must be put last
- Can't put a block around several cases, so
sswitch
is incompatible to Duffs device. - The to-be-switched value is always copied - there is no automatic deduction for lvalues such that they would use references and that only rvalues would be copied
sswitch
can use native break keywords with the expected semantics, works with any type (not just strings) and also supports fall-through like the built-in switch.
Here is how it can be used.
sswitch(s) { scase("foo"): { std::cout << "s is foo" << std::endl; break; // could fall-through if we wanted } // supports brace-less style too scase("bar"): std::cout << "s is bar" << std::endl; break; // default must be at the end sdefault(): std::cout << "neither of those!" << std::endl; break; }Notice that since we insert extra braces between each case label (to prevent the code in between to be executed if we haven't hit a label yet), we can't use a plain "default:" at the end, as would be desired by me. We can jump inside if we want
sswitch(s) { test: std::cout << "this will be output after foo/bar!" << std::endl; break; scase("foo"): { std::cout << "s is foo" << std::endl; goto test; } // supports brace-less style too scase("bar"): std::cout << "s is bar" << std::endl; goto test; // default must be at the end snodefault("neither foo nor bar!?"); }
Please tell me what you think about it and whether you find any problem! Hope you like this little helper!
Ich sehe keine offensichtlichen Probleme. Gute Idee. Ich denke nicht, ich würde es in der Produktion Code verwenden, es ist ein bisschen wie ein Hack:-D
ReplyDeleteHi,
ReplyDeleteI am trying to reach you. Can you kindly give me your email address. You can reach me at savinirs.varadan@gmail.com. I tried using itb@jabber.org but that dosent seem to work.
Thanks,
Srinivasa Varadan.
The point of switch is that it is O(1). Your solution is O(n), and is therefore not a good idea.
ReplyDeleteI guess maybe you could do something interesting using hashing and lambdas.
@Srinivasa: Read his email address again. You missed out a character.
ReplyDelete@Mathias Gaunard
ReplyDeleteswitch is not O(1) in the general case. If the compiler can generate a simple formula and build a jump table, it is. But more often than people think, the compiler will generate a dichotomic search in a table containing the case values.
For small number of cases it will even generate the same code as an if/else cascade.
The choice of algo depends on the compiler, the destination machine and the case values.
A compiler is always able to produce a jump table, regardless of the complexity of the formula.
ReplyDeleteSwitching to another asymptotically worse method for small values doesn't change the fact that it is O(1), since the bound is a constant.
You may take a look at my solutions at http://programming.sirrida.de/programming.html#c_case_of_string.
ReplyDeleteThe fastest presented solution is case_map.c which uses an optimized (not necessarily perfect) hash container created at run time the first time the switch is used.
It even runs under plain C. C++ is not needed.
Harrah's Cherokee Casino & Hotel - Mandara
ReplyDeleteInformation and Reviews about Harrah's Cherokee Casino & Hotel in Mandara, including 태백 출장안마 Rooms, Phone number, Address, Website, Phone number, Website, 시흥 출장마사지 Address, Website, Rating: 4.6 · 부산광역 출장마사지 21 안산 출장안마 reviews 밀양 출장샵
Hello nice bllog
ReplyDelete